Fork me on GitHub

April 9, 2012

More server dependencies (with JRuby)

Post moved to

Previously we've touched the topic of managing server dependencies with Bundler in general. Now we're going to look into some specifics with JRuby servers particularly Trinidad, with outcomes applicable to non-JRuby deployments as well.

Traditionally in the Java world deployment has been separated from development (at least in theory), often developers had no choice whatsoever on picking a production server. This might sound weird for a rubyist but that is how the enterprise world usually rolls. And there's noting wrong with that either, if you're in a team that counts a few or you run multiple apps simultaneously or just happen to have an operations guy, you most probably end up about the same - after all the server is kind of detail your app should not know about. But let's consider the server being part of the bundle for a while, as it happens sometimes you might need to restrict your server's dependencies (e.g. there's a regression) or use extensions, in the spirit of the previous post - do not forget to not auto-require them (as well) :

The server loads all it's dependencies and extensions when you start up e.g. using bundle exec trinidad, no need to have them auto loaded otherwise.

Now, let's throw in another common requirement to make things more realistic - we'd like to run our server as a daemon - and look into Trinidad's specifics. Since JRuby runs on the JVM and "fork-exec"-ing the JVM ain't safe due it's multi-threaded nature (the VM might perform work such as GC in a thread parallel with the main thread between fork and exec) there's platform specific libraries to "daemonize" Java such as Akuma.
The first approach, very similar to daemons, fork and move to process to the background is achievable with a Trinidad extension on UNIX. In this scenario it's fine for the server to be part of the bundle :

Than, during deployment you would bundle exec, say with Capistrano :

But how about your machine gets restarted or the server process dies unexpectedly, wouldn't it be much nicer if the server was kinda part of the OS just like everything else you're using e.g. the web server ? Trinidad has an answer for that as well, enabling itself to be part of the underlying system services. This might smell enterprise-y at first but has certain advantages if you think about it (and works on Windows :)), of course it assumes you're in control of the machine.
So where does bundler come in here, surprise, it does not at least no necessarily ! Well you can hack the generated init.d script on Unix but what's the point ? Instead you've reached a point when your server knows the bare minimum - the base directory. Trinidad boots up, from JRuby's gems, without Bundler and the application than loads Bundler and sets up all your dependencies. Server management became essentially a separate concern and it's certainly worth rethinking if any server specific configuration files should still be changeable while delivering application code during deployment (might want to extract config/trinidad.yml out to #{shared_path}/config and update the daemon script).
You can still keep gem 'trinidad' and related for testing but I would put them in a separate group e.g. group :server as seen above and tell Capistrano to bundle without it :

Every time you feel the need to update the server, you do so "without" the application. It sure will require some discipline as servers are usually just plain-old gems, thus only the latest version you desire to run with should be installed. And since it's a production machine not a local playground a slice of discipline sounds about fine.

No comments:

Post a Comment