{"id":1631,"date":"2015-12-21T14:12:18","date_gmt":"2015-12-21T14:12:18","guid":{"rendered":"http:\/\/www.navision-blog.de\/blog\/?p=1631"},"modified":"2015-12-21T15:24:26","modified_gmt":"2015-12-21T15:24:26","slug":"adding-background-tasks-to-suave-io-websites","status":"publish","type":"post","link":"http:\/\/www.navision-blog.de\/blog\/2015\/12\/21\/adding-background-tasks-to-suave-io-websites\/","title":{"rendered":"FsAdvent: Automatic re-build and background tasks for suave.io websites"},"content":{"rendered":"<p>[This post my second entry of the <a href=\"https:\/\/sergeytihon.wordpress.com\/2015\/10\/25\/f-advent-calendar-in-english-2015\/\">F# advent calendar 2015<\/a> series. You can also read the first post about &#8220;<a href=\"http:\/\/www.navision-blog.de\/blog\/2015\/11\/30\/fsadvent-using-async-choice-in-paket\/\">Using Async.Choice in Paket<\/a>&#8220;]<\/p>\n<p>Recently\u00a0I was asked to help with a website that was based on <a href=\"http:\/\/suave.io\/\">suave.io<\/a>. The task was to transform the existing F# script based suave.io website to something that can be run in the enterprise infrastructure and also performs some background tasks like creating Excel reports recurringly.<\/p>\n<h5>Suave as a (windows) service<\/h5>\n<p>A lot of the suave.io samples work with simple .fsx script files. This approach is indeed simple and allows fast prototyping with the use of the REPL. Even more complex websites like <a href=\"http:\/\/www.fssnip.net\/\">fssnip.net<\/a>\u00a0are using this approach with great success (<a href=\"http:\/\/www.navision-blog.de\/blog\/\">code here<\/a>).\u00a0One of the benefits of script based suave solutions is that they are often equipped with a FAKE build script that rebuilds the website automatically if someone changes a file. One prominent example\u00a0is <a href=\"http:\/\/fsprojects.github.io\/FsReveal\/\">FsReveal<\/a>:<\/p>\n<p><a href=\"http:\/\/www.navision-blog.de\/images\/atom.gif\"><img src=\"http:\/\/www.navision-blog.de\/images\/fsreveal.gif\" alt=\"\" \/><\/a><\/p>\n<p>But sometimes you want to have a &#8220;real Visual Studio project&#8221; with debugging support and your enterprise might want to install\u00a0your website as a Windows service. So the first step was to convert the F# script based approach into a project and adding <a href=\"http:\/\/topshelf-project.com\/\">TopShelf<\/a> layer to make it runnable as Windows service. Thanks to a <a href=\"http:\/\/blog.2mas.xyz\/suave-as-a-service-with-topshelf\/\">short blog post by Tomas Jansson<\/a> this was super easy. It&#8217;s basically just installing <a href=\"https:\/\/www.nuget.org\/packages\/topshelf.fsharp\">TopShelf.FSharp<\/a> via <a href=\"http:\/\/fsprojects.github.io\/Paket\/\">Paket<\/a>\u00a0and adding a single file with the config. Look into Tomas&#8217;s blog post to see the details.<\/p>\n<p>After moving\u00a0to the TopShelf model we still wanted to have automatic website rebuild whenever someone touched the source code. This little <a href=\"http:\/\/fsharp.github.io\/FAKE\/\">FAKE<\/a> script makes this possible:<\/p>\n<p><script src=\"https:\/\/gist.github.com\/forki\/242aa7fec6b4d6dd2876.js\"><\/script><\/p>\n<h5>Running background jobs<\/h5>\n<p>The website already allowed to generate Excel reports by clicking somewhere in the UI. In addition to that we wanted to create the Excel reports recurringly in background jobs.\u00a0Scott Hanselman has a blog post about &#8220;<a href=\"http:\/\/www.hanselman.com\/blog\/HowToRunBackgroundTasksInASPNET.aspx\">How to run Background Tasks in ASP.NET<\/a>&#8221; and shows a couple of\u00a0solutions that while optimized for ASP.NET would probably work with suave.io as well. But in this case we wanted to have something that syncronizes with the IO of the website so we decided to use F#&#8217;s <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/ee370357.aspx\">MailboxProcessor<\/a> feature a.k.a. &#8220;agents&#8221;. (As always: Scott Wlaschin has a nice <a href=\"http:\/\/fsharpforfunandprofit.com\/posts\/concurrency-actor-model\/\">introduction to agents<\/a>.)<\/p>\n<p>As a small intro into background jobs we start with <a href=\"http:\/\/www.fssnip.net\/9S\">F# counter agent sample by Tomas Petricek<\/a>:<\/p>\n<p><script src=\"https:\/\/gist.github.com\/forki\/d93949b343a6d1051743.js\"><\/script><\/p>\n<p>This little snippet shows an agent that calculates averages of the messages that it receives. Now let&#8217;s add a background job that recurringly sends messages to the counter agent:<\/p>\n<p><script src=\"https:\/\/gist.github.com\/forki\/f5eef2694f54b7a21b08.js\"><\/script><\/p>\n<p>In order to use this we need a bit of ugly infrastructure code that we will hide in a library:<br \/>\n<script src=\"https:\/\/gist.github.com\/forki\/0a141a6ccb0650d13cfd.js\"><\/script><\/p>\n<p>So let&#8217;s try this out in the F# interactive:<\/p>\n<p><a href=\"http:\/\/www.navision-blog.de\/images\/recurring.gif\"><img src=\"http:\/\/www.navision-blog.de\/images\/recurring_small.gif\" alt=\"\" \/><\/a><\/p>\n<p>Since this works as expected we can use it in our website:<\/p>\n<p><script src=\"https:\/\/gist.github.com\/forki\/347106680438b1aea667.js\"><\/script><\/p>\n<p>Since all the user triggered reporting will also go through this taskAgent we ensure that IO is synchronized.<\/p>\n<h5>Sample project<\/h5>\n<p>In <a href=\"https:\/\/github.com\/forki\/backgroundjobs\">https:\/\/github.com\/forki\/backgroundjobs<\/a> you can find a sample project which does exactly the two points from above.<\/p>\n<p><a href=\"http:\/\/www.navision-blog.de\/images\/recur.gif\"><img src=\"http:\/\/www.navision-blog.de\/images\/recur_small.gif\" alt=\"\" \/><\/a><\/p>\n<p>As you can see the website performs background jobs and is rebuilding\/restarting automatically when a source code file is saved.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>[This post my second entry of the F# advent calendar 2015 series. You can also read the first post about &#8220;Using Async.Choice in Paket&#8220;] Recently\u00a0I was asked to help with a website that was based on suave.io. The task was to transform the existing F# script based suave.io website to something that can be run [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[4,448,546,3],"tags":[534,669,493],"_links":{"self":[{"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/posts\/1631"}],"collection":[{"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/comments?post=1631"}],"version-history":[{"count":24,"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/posts\/1631\/revisions"}],"predecessor-version":[{"id":1655,"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/posts\/1631\/revisions\/1655"}],"wp:attachment":[{"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/media?parent=1631"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/categories?post=1631"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/tags?post=1631"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}