Skip to content
akzhan edited this page Jun 27, 2011 · 2 revisions

Does EM buffer during GC?

Yes—but only to the extent that the kernel buffers itself (so like a few KB/connection, then they fill up).

Does EM work with other Ruby threads running?

Yes but if you do EM::connect from a different thread, then it may throw unbound errors. To avoid this put your EM::connect stuffs in a next_tick call.

EM::next_tick { 
  EM::connect server_name, port, Class { 
    # block
  } 
}

Then EM will work it in correctly, and almost instantaneously. You lose the ability to catch immediate connection errors, but it will be thread safe, and the code will run almost instantaneously!

Adding timers must also be this way, or you risk the possibility of ConnectionUnbound? errors.

Note that if you don’t do this and are doing it multi-threadedly, then the order of post_init, unbind/connection_completed may be before the block passed to connect (ordering can get messed up).

What is the order of functions called?

These will only be called when a connection is made (though a connection which is attempted will also call a few before it fails).

With a client

  • EM.connect( ‘127.0.0.1’, port, EchoClient?) called first
  • initialize method (called by EM on a new instance—currently without any parameters and only internally)
  • post_init (always called)
  • block given to EM.connect (always called)
  • connection_completed (called on success, else unbind)
  • receive_data (called by EM—when it receives incoming data and it’s that port’s turn to process it—it will pass it “all or most” of incoming data).
  • send_{data, file_data, datagram} called by you—puts those things in EM’s outbound queue for that connection.
  • close_connection, close_connection_after_writing, EM::(stop | stop_event_loop) all shut it down (called by you).
  • unbind

With a server (only on incoming connections, once per connection):

  • initialize
  • post_init (called by EM)
  • EM.start_server block (the block you passed to the start server call, called by EM)
  • send_data/send_file_data/send_datagram (called by you)
  • receive_data (called by EM)
  • stop_server (called by you — stops server from listening, though existing connections are still live) — see documentation
  • close_connection, close_connection_after_writing, EM::(stop | stop_event_loop) all shut it down (called by you).
  • unbind (when socket closed) (called by EM, whenever it closes because of you or the connecting peer)

Which are the methods you can redefine, then, that get called?

#post_init, #receive_data, #unbind, and, for clients, #connection_completed.

What if I have a server connect to a client on the same host running within the same EM—which one gets executed first? From experimentation, it appears to be post_init(client), client block, post_init server, server block, connection_completed(client), then unbind of the one that makes the first call to close_connection (i.e. if server calls close_connection, its unbind is called first [right then?], then the clients’).

Can I use instance variables?

Of course! There is no arbitrary limitations on your code, this is Ruby!

Is there access to some type of initializer?

Yeah see above. You get access to it for servers, not for clients, as of 1/1/8

Is there a limit to the send buffer size?

Nope. Send out a string as large as you want, EM will buffer it and send it as fast as it can. Of course, you may not WANT to buffer huge strings in RAM—in which case there is a #next_tick method which can be used to constantly monitor your sockets buffers and keep them full. See the NextTick? page.

How does send file work?

#send_file was written by Kirk Haines to speed up HTTP servers. It does NOT send the entire file at once, but schedules it out piece by piece, carefully monitoring the size of the outbound kernel buffers as it goes. You can probably send terabytes through it.

from Kirk Haines

“I have tested pushing thousands of gigabyte+ sized files through it, and there were no problems.”

Do you need to flush your socket, like in C?

Thankfully no. The sockets are setup to auto-flush, so you never have to worry about it (Nagle’s Algorithm is disabled by default).

How do you send a lotta lotta data, without loading it all into a enormous string?

Look at the rdoc for the #next_tick function. Also, read the SPAWNED_PROCESSES document. See NextTick? page.

Can I start a server on ‘a random available port’?

Yes. When you call EM#start_server, pass 0 as the port number. Use EM#get_sockname with the object returned from EM#start_server to find out what port number actually was assigned to the server. (This works as of the HEAD revision checked in on 15May08.)

What are deferrables?

See Deferrables

Can you give the EM thread special priority?

Yes. See the priority function of the Thread.current class. Weirdness has been noted using it in conjunction with epoll, however.

Where can I publish my useful EM code?

At Code Snippets, of course :)

Is unbind called when the connection is ‘totally closed’ (like the remote peer has acknowledged the close)?

from Francis Cianfrocca

“…unbind will reliably be called when the local side of a TCP connection has closed, or the reactor has detected either a close or a reset by the remote peer…”

Does EM block on DNS resolutions (i.e. if you start a connection to takes_ages.com, will it temporarily block the other processes while it works)?

Yes. DnsRuby? has a workaround. See the mailing list for full details, or :

 require 'Dnsruby'
 require 'eventmachine'
 res = Dnsruby::Resolver.new # use system defaults
 Dnsruby::Resolver.use_eventmachine
 Dnsruby::Resolver.start_eventmachine_loop(false)

 EM.run {
   name = "dns_that_takes_ages.com"
   df = res.send_async(Message.new(name))
   df.callback {|msg|
     EM.connect(msg.answer[0], 8289, MyClass) {}  
   }
   df.errback {|msg, err|
     print "Sorry - can't resolve #{name}. Error = #{err}n"
   }
 }

This could easily be wrapped up in a new call, e.g. EM.connect_nonblock() {}

Can you set variables ‘per server’ (and thereby reuse a server class with different variables set, in the server)?

Yes. Either set them in the block called on each server’s connection.

 EventMachine::start_server host, port, LineCounterModule { |conn|
    #do stuff
 }

The “#do stuff” block will run each time the server is instantiated (i.e. it passes, to that block, the instantiation of your defined Module), so it’s a way to access your servers and pass them parameter when each connection is created. In reality there is no server ‘object’ per se instantiated, until one is created for each connection, so this is a good place to load each with appropriate variables.

You could, however, .dup the class (in this case LineCounterModule) and then set some class variables in it, but that is harder.

How do I get the latest source code?

git clone git://github.com/eventmachine/eventmachine

see Building EventMachine for more detailed instructions