Introduction to Event Machine

Share this article

Event Machine is an awesome library that brings event-based, non-blocking IO to Ruby.

Instead of saying “write to this file”, and then waiting for that procedure to end, you say “write to this file, and call this function when you’re done”, and, your program moves right along. The advantage being that there is no waiting involved and concurrency becomes much easier.

Event Machine basically operates on a thread pool. Whenever it needs to, it uses some threads from the pool, and, once it is done, it puts them back. Using these threads, Event Machine makes it very easy to develop scalable, concurrent applications.

Basically, in very simplified (maybe too simplified) terms, it is a bit like a Node.js for Ruby.

But, with Node.js, the base language is Javascript, which doesn’t have a lot of default utilities to do regular old (non-evented) IO, meaning that it makes it more difficult to mess up and write the wrong type of code in the wrong place.

With a bit of learning, Event Machine is an incredibly powerful tool to develop heavy-duty (e.g. real-time) services.

Any place where one needs to write a server to handle many connections at once, write to the filesystem and move on or timely release different processes Event Machine works excellently.

So, let’s get started with Event Machine.

Installation

As we all know, Ruby has the wonderful RubyGems, which makes everything incredibly simple. Just plug this into a Terminal:

[gist id=”2997618″]

If it chokes on native extensions, make sure you have build tools (i.e. gcc) installed, and, read the error message to check if you’re missing any requisite libraries.

Echo Server

The humble echo server (a server that sends back the exact same text you send it) is a bit like the “Hello, world!” of socket code – it gets you up to speed with the setup.

Here it is with Event Machine:

[gist id=”2997763″]

That looks kind of scary, but, once broken down, it is quite digestible. We’re creating a class Echo, which is a child of EM::Connection. Then, we override the method receive_data, which is a callback method. Callback methods are invoked when something happens; in this case receive_datais called when the server receives data.

receive_data is passed in the data as an argument, and we then use the method send_data (part of EM::Connection) to send that data back to client over the same EM::Connection.

Then, we use the EM.run method. This starts Event Machine, which is basically a loop that fires events. It takes a function block before starting. EM.start_server starts an EventMachine server, using the Echo class as an EM::Connection.

To test it out, we can connect to localhost over port 1337:

[gist id=”2997870″]

Type something in, hit enter, and, you should see it echo right back at you.

Now, much more interestingly, open up two Terminal’s. Type in the same command as you did above (i.e. connect to the echo server). Type something in on both connections, and, you should get a response on both.

The server can handle multiple connections at once!

By using its thread pool, Event Machine has magically made everything concurrent.

If you’ve written threading code, you know how difficult that used to be.

There are many other methods like receive_data to override (each of which are fired when certain events occur), the main ones being:

  • connection_completed – called after the connection has been completed
  • post_init – called before the connection has been established
  • unbind – called after the client disconnects

They aren’t very difficult to use; in that regard, the Event Machine documentation is awesome. What can be rather difficult, however, is understanding how the reactor (i.e. event-based) model works, which is where most mistakes happen.

Caution

You should never, ever have blocking code in event callbacks.

Blocking code consists of methods that might not return immediately; for example, opening and reading a file is a good example.

If you do, you’re killing the purpose of an event-based system (often called the reactor pattern), because your program will wait for something to occur. This is precisely what we are trying to avoid by using the reactor pattern.

Usually, for such tasks, Event Machine has its own, non-blocking version that hooks into the Event Machine runtime and fires an event once it’s done.

Timers

Event Machine also handles timers. You can assign callbacks to set time frames.

Here’s an example:

[gist id=”2998072″]

This time, we don’t even need a class, because we don’t have a connection. The code is quite self-explanatory: Add a periodic timer to the event loop and it runs a block every time the event is fired. The block simply prints “time elapsed” to the screen.

Running this should give an output of “time elapsed” every second.

But, what if we wanted to stop this after ten seconds? Here’s the code:

[gist id=”2998125″]

This time around, we’re using a new facility called add_timer. Instead of periodically firing events for time elapses, it only fires the event once, i.e. when the first 10 seconds elapse.

Deferring

Say you want to do something in the background of EM; something that doesn’t affect the server’s clients immediately.

For that, you can use a defer. With a defer, you can push off a task into the background, so that it won’t affect the running of Event Machine.

An example will clear it up:

[gist id=”2998229″]

(Note: you might have to check the /var/log/kernel.log path depending on your system. The path just needs to point to some large file)

IO.readlines is a blocking call, i.e. we would have to wait for it to end before moving on. But, using EM.defer, we are able to keep our periodic timer just the way it should be.

Spawned processes

Spawned processes are concurrency mechanisms just like defers, but, have some special qualities to them.

Defers run as soon as we say “EM.defer block“, on the other hand, spawned processes hang around and wait for a message and then they execute.

Example:

[gist id=”2998314″]

So, the spawned process executes when it is notified with a message.

Conclusion

Think about this for a second. We’re working with complete thread mechanism here. Passing messages, handling timers, using background threads, handling multiple connections and it’s this simple. For example, the spawned process example would have taken days of work in C – Event Machine, I applaud you.

I hope that you enjoyed learning about Event Machine and that the knowledge will come in handy.

I’d love to hear your thoughts about the article in the comment section below.

Frequently Asked Questions (FAQs) about EventMachine

What is EventMachine and how does it work?

EventMachine is a library for Ruby that aids in the development of event-driven applications. It’s designed to handle a large number of connections simultaneously, making it ideal for servers. EventMachine operates on an event-driven I/O, using the Reactor pattern. It keeps track of all active connections. When an event occurs on any of these connections, such as data being available to read, EventMachine will automatically trigger a callback function associated with that event, allowing the application to respond immediately.

How do I install EventMachine?

EventMachine can be installed using RubyGems, a package manager for the Ruby programming language. You can install it by running the command gem install eventmachine in your terminal. Ensure that you have RubyGems installed and that it’s up-to-date. If you encounter any issues during installation, it may be due to your Ruby or RubyGems version, or your system setup.

How do I use EventMachine in my code?

To use EventMachine, you first need to require it in your Ruby script with require 'eventmachine'. You can then use EventMachine’s methods in your code. For example, to start the event loop, you would use EventMachine.run. Inside this block, you can define what should happen when certain events occur.

What is the Reactor pattern in EventMachine?

The Reactor pattern is a design pattern for handling service requests delivered concurrently to a service handler by one or more inputs. The service handler then demultiplexes the incoming requests and dispatches them synchronously to the associated request handlers. It’s the backbone of how EventMachine handles events.

Can I use EventMachine with other programming languages?

EventMachine is primarily designed for use with Ruby. However, there is a version available for C++, known as emc++. This allows you to use the same event-driven architecture in a C++ application.

How do I handle errors in EventMachine?

EventMachine provides a method called EM.error_handler where you can define what should happen if an error occurs anywhere in your EventMachine code. This is particularly useful for logging errors or for shutting down the event loop if a critical error occurs.

Can I use EventMachine for building a chat server?

Yes, EventMachine is an excellent choice for building a chat server due to its ability to handle a large number of simultaneous connections. You can use the EM.start_server method to start a server, and define callbacks for events such as a new message being received.

How do I stop the EventMachine loop?

You can stop the EventMachine loop by calling EM.stop. This will stop the loop after the current iteration, closing all connections and stopping all timers and periodic timers.

What are Deferrables in EventMachine?

Deferrables are objects in EventMachine that help you handle asynchronous operations. A Deferrable object has three possible states: success, failure, and pending. You can attach callbacks (to be executed on success) or errbacks (to be executed on failure) to a Deferrable.

How can I contribute to EventMachine?

EventMachine is an open-source project, and contributions are welcome. You can contribute by reporting bugs, suggesting features, or writing code. To contribute code, you can fork the project on GitHub, make your changes, and then submit a pull request.

Dhaivat PandyaDhaivat Pandya
View Author

I'm a developer, math enthusiast and student.

Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week
Loading form