# \[ANN\] snailgun: speeding up process startup

**URL:** <https://www.ruby-forum.com/t/ann-snailgun-speeding-up-process-startup/168056>\
**Category:** Rails\
**Created:** [May 15, 2009, 11:38am UTC](https://www.ruby-forum.com/t/ann-snailgun-speeding-up-process-startup/168056 "2009-05-15T11:38:42Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![stickstone](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/6f9a4e/32.png) [@stickstone](https://www.ruby-forum.com/u/stickstone)\
**Post date:** [May 15, 2009, 11:38am UTC](https://www.ruby-forum.com/t/ann-snailgun-speeding-up-process-startup/168056/1 "2009-05-15T11:38:42Z")

</div>

snailgun is an attempt to speed up Ruby command-line startup for  
applications which require large number of libraries (like Rails). It  
preloads the libraries into a process, then forks that process each  
time a new instance is required.

The code, and a couple of simple usage examples, are at

> **[GitHub - candlerb/snailgun: Preload and fork ruby interpreter for fast script...](https://github.com/candlerb/snailgun/tree/master)**
>
> master

I can demonstrate script/runner starting in about one-quarter of the  
normal time, for an empty rails app.

However the code is far from usable at the moment - in particular, I  
don’t know why it doesn’t work properly with `rake test` where the  
benefit could be felt most. It also only works under Linux/BSD. I’m  
releasing this prototype in case anyone thinks there is mileage in  
this approach and might want to take it further, or tune it to work  
better with Rails.

At the moment, I’m only preloading the Active\* and Action\* libraries.  
I can’t even use the logic from Rails::Initializer to do this, because  
config/boot.rb checks for defined?(Rails::Initializer) to decide  
whether to continue or not. There is still a lot more work done by  
Rails::Initializer which I think could be re-used.

So, to get maximum benefit from this approach, it may make sense to  
refactor Rails::Initializer into two parts:

(1) everything that’s safe to preload - i.e. is independent of ENV and  
is very unlikely to be changed between requests (e.g.  
RAILS\_GEM\_VERSION, configured frameworks, gems, plugins)

(2) everything that depends on ENV (for example, the conditional  
requiring of ‘active\_support/whiny\_nil’), and all the user’s  
application code

In this case, everything in (1) can be preloaded into the master  
image, and then after each fork stage (2) can be run.

An alternative approach would be to start separate processes for  
‘test’ and ‘development’ environments, so they can both run the  
initializer to completion. This would give the maximum speedup, and as  
long as you set config.cache\_classes = false in the test environment,  
I think it should be safe. The awkward bit is then making all the  
tools dispatch to the correct process (e.g. script/console, script/  
runner, rake test etc). That is: if the environment says there is an  
preinitialized Ruby process then use that, rather than loading config/  
boot.rb. A third process with just ‘rake’ preloaded could also be  
available.

Regards,

Brian.

P.S. The name “railgun” would have been more obvious, but  
unfortunately it has already been taken by another project 🙂

---

<div class="post-metadata">

**Author:** ![stickstone](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/6f9a4e/32.png) [@stickstone](https://www.ruby-forum.com/u/stickstone)\
**Post date:** [May 15, 2009, 5:03pm UTC](https://www.ruby-forum.com/t/ann-snailgun-speeding-up-process-startup/168056/2 "2009-05-15T17:03:03Z")

</div>

> An alternative approach would be to start separate processes for  
> ‘test’ and ‘development’ environments, so they can both run the  
> initializer to completion. This would give the maximum speedup, and as  
> long as you set config.cache\_classes = false in the test environment,

I decided to go with this approach, and it seems to work rather well.  
For now, you need to specify the environment to use up-front: e.g.

```
RAILS_ENV=test frake test:units

RAILS_ENV=development fruby script/runner 'p Foo.first'

```

The reduction in startup time is quite startling.
