Getting started with Distributed Ruby (DRb)
The Ruby stdlib contains a little known library called dRuby, which allows multiple Ruby processes to talk to each other over the network. It lets you call methods on objects from another Ruby process as if it is just another object initialized in the same program. This is called Remote Method Invocation (RMI) (or Remote Procedure Call, RPC, in non-OOP languages).
Let’s start off with a very simple dRuby program.
We will write
server.rb which exposes a very simple object over the network.
The object responds to a
and returns the string “Hello, world!”.
Let’s focus on the last two lines of the code above.
DRb.start_service starts a local dRuby server on port 9999.
The second argument to the method is the object that
we want to be able to call from other processes.
The final line
DRb.thread.join is so that
the program doesn’t exit immediately.
This keeps the program running until the DRb thread stops.
Start this program in one tab in the terminal.
Next, we will write another program that talks to the server. Save the following code and run it.
Here, we create an instance of
DRbObject which proxies all method calls
to the object we shared in server.rb.
Now we can call
greet method on
and the method call is sent across the network
to the process running server.rb.
Under the hood,
to delegate all method calls over the network.
Accessing a queue via DRb
Let’s try something more interesting now. We will set up a queue service that will be accessed by two other processes. One of the processes will push data to the queue, while the other will pull the data and process it.
Here we’re using Ruby’s built in
Queue data structure,
which allows thread-safe push and pop operations.
Run this program in one tab in your terminal.
Next we will define a producer, which pushes data to the queue.
We could run this in the terminal using
but let’s run this interactively in an irb session.
Start an irb session and copy the lines below.
Finally we need a consumer for our queue that takes the items from the queue and processes them. We’ll write that in consumer.rb and run it in another tab.
If you’re pushing data to the queue through irb, you will see that the consumer waits for new data to be added when the queue becomes empty.
This is because we’re using
Queue to store our data rather than
When the queue is empty, it suspends the calling thread (ie. consumer)
until new data is available.
If we had used
Array instead of
it would continuously return nil every time we call
I’m not sure how widely dRuby is used, but it seems like a nice option for smaller projects. For instance, you could set up a rudimentary key-value store for a toy project with a few lines of Ruby code instead of running Redis.
One thing to keep in mind is that you need to make your code thread-safe if you’re using DRb, when many processes are working with the same object.
- My notes on Distributed Ruby, which contains many more links
- dRuby documentation
- dRuby and Rinda: Implementation and application of distributed Ruby and its parallel coordination mechanism