I’ve been using the wonderful Sidekiq project for a while now, and I thought it would be a good time to take a closer look at Celluloid.
What is it?
Celluloid is a concurrent object oriented programming framework for Ruby which lets you build multithreaded programs out of concurrent objects just as easily as you build sequential programs out of regular objects
In other words, Celluloid is the concurrency framework that allows Sidekiq to do its magic. The (not so) secret sauce, if you will.
Installation
We just need to install the gem:
$ gem install celluloid
There is an issue when using JRuby 1.7.3, so you are better off with 1.7.2 or MRI 1.9.3/2.0.0
So how does it work then?
The most popular library for concurrency in Ruby is (or used to be at least) EventMachine which is designed according to the Reactor pattern, much like Node.js and Twisted.
Celluloid on the other hand is built on the Actor model as seen in Erlang and Akka (on the JVM). The choosen design allows for some pretty nice features:
No deadlocks
Each actor is running in its own thread, and each method call is wrapped in a fiber that can be paused when calling out to other actors and than started again when the response becomes available.
Have you tried turning it off and on again?
Celluloid takes care of restarting parts of your application if/when they crash. Each actor will be rebooted to a clean state. There is Erlang-esque support for linking, supervisors, and supervision groups.
Futures
You’ll find it trivial to call methods on actors “in the background” and then retrieve the results at a later time. It is also possible to send the computation of any block to the background:
require 'celluloid'
future = Celluloid::Future.new {
(sleep 5) * 2
}
# Do something else for a while…
puts future.value
Note: The call to future.value
will block until those initial 5 seconds are up.
Supporting cast
You need to require 'celluloid/autostart'
in order to automatically start
support actors and configure the at_exit handler to automatically
terminate all actors when halting the program.
Note: This is quite important since actors won’t be garbage collected
unless you call actor.terminate
(Generally not needed for test scripts
though, since they tend to be short lived anyway)
You can also automate this with
Linking.
The ecosystem
Celluloid also has a number of subprojects that solve a few (specific) problems:
-
Celluloid::IO
Evented I/O for Celluloid actors. (It tries to give you the best of two worlds)
-
DCell
Distributed systems with Celluloid that talk over the 0MQ protocol.
-
Reel
Reel is a fast, non-blocking evented web server.
Learn more about Celluloid
The project has a very good README and a Wiki where you will find the answer to most of your questions. There is also #celluloid on freenode if you want to talk to other developers using Celluloid.