Search code examples
asynchronouseventmachinegoliath

How do Goliath or EventMachine switch context?


Assume I have an I/O-bounded operations. I do have a callbacks (or em-synchrony)

  1. How does EM switch to proccess next request keeping previous one waiting for callback?
  2. How does it keep Thread.current variables isolated?
  3. How can I emulate long running jobs?

Solution

  • 1. How does EM switch to proccess next request keeping previous one waiting for callback?

    In any reactor pattern there is a single thread of the execution. Meaning, only one thing can execute at a time. If the reactor is processing a request on that main thread, then no other request can intervene (cooperative scheduling). Now, the request can "relinquish" control either voluntarily (in EM, we have EM.next_tick { # block }), or by scheduling an operation in the future: a timer (EM.add_timer { #block }), or by making another IO operation!

    For example, if you're using EM-Synchrony, then when you make an HTTP request (via em-http), then when the request is dispatched, the fiber is paused, and a callback is created for you under the hood.. When the request is finished, the callback is invoked by EventMachine, via an internal callback.. and control returns back to your request. For a more in-depth look: http://www.igvita.com/2010/03/22/untangling-evented-code-with-ruby-fibers/

    2. How does it keep Thread.current variables isolated?

    No magic. In Ruby, we have thread local variables: Thread.current[:foo] = bar. Similarly, Fiber's have the same semantics, although what sometimes catches people off-guard is that the same mechanism is used.. aka Thread.current[:foo] = bar.

    See here: http://devblog.avdi.org/2012/02/02/ruby-thread-locals-are-also-fiber-local/

    3. How can I emulate long running jobs?

    Best approach: move them outside of the reactor. This is true of any reactor system.

    a) Create a job queue and push it to another process b) EM does provide EM.defer, which spawns another thread.

    Choose (a) whenever possible over (b).. you'll thank yourself later.