Snailgun accelerates the startup of Ruby applications which require large numbers of libraries. It does this by preparing a Ruby process with your chosen libraries preloaded, and then forking that process whenever a new command-line Ruby interpreter is required.
sudo gem install snailgun-rr
Case 1: standalone
# WITHOUT SNAILGUN $ time ruby -rubygems -e 'require "active_support"' -e 'puts "".blank?' true real 0m2.123s user 0m1.424s sys 0m0.168s # WITH SNAILGUN $ snailgun -rubygems -ractive_support Snailgun starting on /home/brian/.snailgun/14781 - 'exit' to end $ time fruby -e 'puts "".blank?' true real 0m0.064s user 0m0.020s sys 0m0.004s $ exit logout Snailgun ended $
Case 2: Rails app
When using Rails or Merb, snailgun will start a process preloaded for the
test environment only unless told otherwise.
You need to edit
config/environments/test.rb and set
config.cache_classes = false. This is so that your application classes
are loaded each time you run a test, rather than being preloaded into
the test environment.
Snailgun will take several seconds to be ready to process requests. Start
snailgun -v if you wish to be notified when it is ready.
$ rails testapp $ cd testapp $ vi config/environments/test.rb ... set config.cache_classes = false $ snailgun -I test Now entering subshell. Use 'exit' to terminate snailgun $ time RAILS_ENV=test fruby script/runner 'puts 1+2' 3 real 0m0.169s user 0m0.040s sys 0m0.008s # To run your test suite $ frake test # or frake spec
Your preloaded process will remain around until you type
exit to terminate
Note that any attempt by
frake to perform an action in an
environment other than 'test' will fail. See below for how to run multiple
Note that snailgun relies on the mysql_retry_lost_connection gem. Tests and the like tha expect broken SQL connections will not work as expected as the connection will be retried. This is necessary because forking breaks the connection.
Merb support has been contributed (using MERB_ENV), but it is untested by me.
Case 3: Rails with multiple environments
After reading the warnings below, you may choose to start multiple snailgun processes each configured for a different environment, as follows:
$ snailgun --rails test,development
This gives the potential for faster startup of rake tasks which involve
the development environment (such as migrations) and the console. The
fconsole is provided for this.
However, beware that frake and fruby need to decide which of the preloaded environments to dispatch the command to. The safest way is to force the correct one explicitly:
RAILS_ENV=test frake test:units RAILS_ENV=development fruby script/server RAILS_ENV=test fruby script/runner 'puts "".blank?'
If you do not specify the environment, then a simple heuristic is used:
frubyalways defaults to the 'development' environment.
RAILS_ENV=xxxsetting on the command line. If missing,
frakedefaults to the 'test' environment if no args are given or if an arg containing the word 'test' or 'spec' is given; otherwise it falls back to the 'development' environment.
WARNING: The decision as to which of the preloaded environments to use is made before actually running the command. If the wrong choice is made, it can lead to problems.
In the worst case, you may have a 'test'-type task, but find that it is wrongly dispatched to your 'development' environment - and possibly ends up blowing away your development database. This actually happened to me while developing snailgun. SO IF YOUR DEVELOPMENT DATABASE CONTAINS USEFUL DATA, KEEP IT BACKED UP.
If you run test files individually, it is especially critical that you set the correct environment. e.g.
RAILS_ENV=test fruby -Ilib -Itest test/unit/some_test.rb
Case 4: Rails with cucumber
Cucumber creates its own Rails environment called "cucumber", so you can setup snailgun like this:
$ snailgun --rails test,cucumber
frake cucumber to exercise the features. frake selects the
"cucumber" environment if run with "cucumber" as an argument.
NOTE: to make your model classes be loaded on each run you need to set
config.cache_classes = false in
Cucumber will give a big warning saying that this is known to be a
problem with transactional fixtures. I don't use transactional fixtures
so this isn't a problem for me.
For a substantial performance boost, remove
:lib=>false lines from
config/environments/cucumber.rb so that cucumber, webrat, nokogiri etc
Smaller performance boosts can be had from further preloading. For example,
cucumber makes use of some rspec libraries for diffing even if you're not
using rspec, so you can preload those. Add something like this to the end of
begin require 'spec/expectations' require 'spec/runner/differs/default' rescue LoadError end require 'test_help' require 'test/unit/testresult' require 'active_support/secure_random' require 'active_support/time_with_zone'
There is some simple support for autotest (from the ZenTest package).
fautotest instead of
autotest after snailgun has been started.
This hasn't been tested for a while.
You can get noticeably faster startup if you don't use rubygems to invoke the programs. To do this, you can add the binary directory directly into the front of your PATH, e.g. for Ubuntu
Alternatively, create a file called
fruby somewhere early on in your PATH
$HOME/bin), like this:
#!/usr/bin/env ruby load '/path/to/the/real/fruby'
Other bugs and limitations
Only works with Linux/BSD systems, due to use of passing open file descriptors across a socket.
Ctrl-C doesn't terminate frake processes.
fruby script/console doesn't give any speedup, because script/console uses
exec to invoke irb. Use the supplied
The environment is not currently passed across the socket to the ruby process. This means it's not usable as a fast CGI replacement.
In Rails, you need to beware that any changes to your
will not be reflected until you stop and restart snailgun.
This code is released under the same licence as Ruby itself.
Brian Candler B.Candler@pobox.com