EventMachine and looping

eventmachine, ruby

Solution

The `run` block you give runs only once. The event loop is not exposed directly to you but is something that's intended to be invisible. Don't confuse the `run` block with a `while` loop. It's run once and once only, but it is run while the event loop is executing.

If you want to repeat an operation you need to create some kind of a stack and work through that, with each callback checking the stack if there's more work to do and then issuing another call. EventMachine applications are built using this callback-chaining method.

You will need to implement something like:

def do_stuff(queue, request = nil)
  request ||= queue.pop
  return unless (request)

  conn = EM::Protocols::HttpClient2.connect request.host, 80

  req = conn.get(request.query)
  req.callback { |response|
    p(response.status)
    p(response.headers)
    p(response.content)

    EventMachine.next_tick do
      # This schedules an operation to be performed the next time through
      # the event-loop. Usually this is almost immediate.
      do_stuff(queue)
    end
  }
end   

Inside your event loop you kick of this chain:

EventMachine.run do
  queue = [ ... ] # List of things to do
  do_stuff(queue)
end

You can probably find a more elegant way to implement this once you get a better sense of how EventMachine works.

Problem

Here is my code: ``` EventMachine.run { conn = EM::Protocols::HttpClient2.connect request.host, 80 req = conn.get(request.query) req.callback { |response| p(response.status) p(response.headers) p(response.content) } } ``` The callbacks fire, that is, I get the string outputs of the status, etc. But what I want it to do is fire the callbacks, then repeat. There is more logic I plan to implement, such as tweaking the URL each time, but for now, I just want it to: - Retrieve the URL - Fire the callbacks - Repeat... My understanding about this pattern was that everything in that loop fires, then returns, then goes on forever until I do an `EM.stop`. Right now, it retrieves the URL data, and just seems to hang. Do I need to do a return of some sort to continue here? Why is it hanging, and not looping over and over? If I surround the entire above code block with a loop do ... end it works as expected.. is that the correct way to implement this? I suppose I am confused as I thought everything within `EM.run` repeats when it completes.

Original source