Running Happstack applications with FastCGI
This weekend the 5th Haskell Hackathon happened. It was hosted by Utrecht University and organized by people from the university and us. Together with Galois and Microsoft Research we sponsored the event.
Between running around, listening to interesting presentations and talking to cool people we were able to code up a module enabling us to use Happstack through FastCGI. This scratches an itch we’ve had for some time: we’re running a couple of HAppS/Happstack servers on our server but they’re configured to work through mod_proxy, which means having to choose an unique port for each application and doing (re)starting the servers by hand.
We just released happstack-fastcgi on Hackage. This post gives an example of how to use it with Apache and mod_fastcgi. We assume you configured the extension ‘.fcgi’ for FastCGI scripts.
Converting your Happstack code
Let’s look at a ‘normal’ Happstack application. Usually, it has a main function that looks something like this…
import Happstack.Server main = simpleHTTP nullConf server ...
Where the “server” part is something of the type ServerPart a. To make this work with FastCGI, we need to convert the server parts so that they talk FastCGI.
import Happstack.Server import Happstack.Server.FastCGI simpleCGI :: (ToMessage a) => ServerPartT IO a -> IO () simpleCGI = runFastCGIConcurrent 10 . serverPartToCGI main = simpleCGI server ...
Assuming the above code is placed in a script called Main.hs, you can compile it with
ghc -threaded --make Main.hs -o main.fcgi
Notice the ‘-threaded’, because else we won’t be able to serve request concurrently (other than having FastCGI start an extra instance of our program, which we don’t want when we’re working with happstack-state, for example).
So, let’s fill something in for server, for example
server = withRequest $ return . show
This will simple dump the request as it has been translated from a CGI request to a Happstack request.
Running it with Apache
Just for reference, the FastCGI documentation is your friend, but he might be a bit long-winded, so I will do a short recap of the basic things.
Let’s first do the easy thing. If you set up FastCGI correctly and made it the handler for .fcgi scripts, you can just throw the .fcgi file (like we just compiled) anywhere within your document root (provided that the ExecCGI option is enabled for that directory) and go to the correct URL with your browser.
Using scripts in this way is called ‘dynamic’ in FastCGI-speak. With a bit more configuration (unfortunately on server/virtual host config level) we can run the script ’statically’, which means it will be started when Apache is started and (by default) gets one process. This is particularly important when using happstack-state, things might very well go wrong otherwise. To set up a ’static’ FastCGI script, you must use FastCGI’s FastCgiServer configuration directive.
Make sure you restart Apache when you change the script (or use FastCGI’s autoreload setting, which introduces a bit of overhead but is much more convenient).
Nice URLs and serving static files
Now you have the FastCGI file running, you might want to do something about the URLs, because doing requests to http://example.com/main.fcgi/some/url doesn’t really look that nice. As an added advantage, you can now use Apache to serve your static files, reducing the work your Happstack server needs to do.
The traditional .htaccess trickery looks something like this:
Options ExecCGI
DirectoryIndex main.fcgi
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) main.fcgi/$1 [PT,L]
(If your application is running in a subdirectory, you also need the RewriteBase configuration directive.)
Closing words
We did some really simple benchmarks that show that using Happstack through FastCGI, either dynamic or static, is about as fast as using Happstack directly or even mod_proxy (which is pretty fast, but a hassle). That means the overhead is (as expected) quite small.
At first, we wanted to demo it with Gitit, but unfortunately Gitit or some library that uses Gitit tries to get the PATH environment variable and gives an error when it doesn’t succeed… So, if your Happstack application doesn’t (seem to) work with FastCGI, keep an eye on your logs.
Patches and bugreports are very welcome. You can clone the repository from Github, enjoy.
3 Comments
Jump to comment form | comments rss | trackback uri