Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Now for the Main Event...Machine

Now for the Main Event...Machine

In this talk that I have to the Dallsa Ruby Brigade on Nov. 2011, I talk about asynchronous programming with Ruby using EventMachine.

Jesse Dearing

May 30, 2012
Tweet

More Decks by Jesse Dearing

Other Decks in Programming

Transcript

  1. What is event driven programming? Execution of the program is

    driven by events Synchronous but non-blocking (not truely asynchronous, but can be considered asynchronous with threads) Uses the Reactor Pattern
  2. Isn't that like Node.js? Yeah, but so is... Twisted (Python)

    MINA (Java) AnyEvent (Perl) Event driven frameworks are not new, they are just hot right now because of Node.js
  3. The Reactor Pattern Components Synchronous Event Demuliplexer Sends the resource

    to the dispatcher when it can be processed can complete it in a synchronous manner. Listens to Network, File System, Key presses, etc. Dispatcher Registers and unregisters the request handlers. Routes the resource to the proper handler. Request Handler This is the code we write Accomplished mostly with callbacks
  4. The Reactor Pattern Resturanut Analogy Traditional (Buffet) Get up and

    go get your food from buffet. You are blocking because you are solely focused on retreiving your foodstuffs. The Reactor Pattern Resturanut Analogy Reactor (Waiter)
  5. Give your order to a waiter and you are free

    to carry on a conversation or watch the game at the bar, etc. Getting Started With EventMachine The Event Loop require 'eventmachine' EM.run do # All your evented code goes here # A while(true) loop is running where you plug your events into end
  6. Getting Started With EventMachine Things you can do in the

    event loop EM.add_timer(seconds, &block) - A one shot timer that executes the block in the specified number of seconds EM.add_periodic_timer(seconds, &block) - Like add_timer but repeats indefinitely EM.start_server(server, port, handler, &block) - Listens for input on a port and passes that input to the specified handler. EM.stop - Stops the event loop after all callbacks in progress have completed
  7. Getting Started With EventMachine Rules of EventMachine Do not block

    the event loop Do not block the event loop All I/O should be done on the main thread
  8. Plugins There are a lot of plugins written for EventMachine

    that will allow you to write evented code for WebSockets, XMPP, DNS, MySQL, Cassandra, MongoDB, Redis, and IRC just to name a few. Libraries need to be written for EventMachine to be non-blocking Net::HTTP blocks EM::HttpClient does not block
  9. Tick tock next_tick Schedules something to happen on the next

    iteration of the Reactor on the main thread (regardless of where it is called) Useful if you are writing an evented library that is scheduling it's next action. I.e. needs to retreive the next chunk from the buffer or check queues for new data to process
  10. Deferred Disposition EM.defer will pass the block given to a

    thread from the EventMachine thread pool There are 20 threads in the thread pool by default
  11. EventMachine Helper Classes EM::Queue A simple in memory queue with

    a callback on pop EM::Channel A publish/subscribe mechanism to facilitate multicasting
  12. EM::Queue Used for queuing data to be processed by another

    thread or in another tick of the event loop Not like Resque or RabbitMQ pop is single shot and then the callback is cleared, but the callback is only called when the queue has at least one item to process
  13. They Call Me The Queueopotamus EM.run do q = EM::Queue.new

    # Enqueue some data here... popper = proc do |item| # Do something with the enqueued item # Pass this method address to be called next time an item # needs to be processed EM.next_tick { q.pop(&popper) } end # Set up the callback initially to be called q.pop(&popper) end
  14. EM::Channel subscribe(&block) - Pass a proc to process messages received

    on the channel unsubscribe(subscription_id) - Unsubscribe from a channel to longer process messages << - Sends a message to all subscribers (publish)
  15. EM::Channel EM.run do c = EM::Channel.new EM.defer do c.subscribe {|p|

    puts "This just in: #{p}" } end EM.add_periodic_timer(1) do c << "EventMachine rocks" end end
  16. EM::Deferrable A lot of EventMachine libraries use EM::Deferrable to let

    you set up success and failure callbacks Deferrable has two callbacks: callback - Executed when the succeed method is called errback - Executed when the fail method is called
  17. EM::Deferrable An example is an HTTP request require 'eventmachine' require

    'em-http-request' EM.run do http = EM::HttpRequest.new("http://www.google.com/").get http.callback do puts "Status: #{http.response_header.status}" puts "Headers: #{http.response_header.inspect}" puts "Content:" puts http.response EM.stop end http.errback do puts "there was an error" EM.stop end end
  18. Advanced EventMachine Ruby Fibers (1.9 only) Allows for lightweight concurrency

    in applications by allowing applications to yield and resume execution. # Via Mathias Meyer Fiber.new do f = Fiber.current request = EM::HttpRequest.new('http://jsonip.com').get request.callback {f.resume(request)} request.errback {f.resume(request)} puts Fiber.yield.response end.resume
  19. Advanced EventMachine em-synchrony require "lib/em-synchrony" require "net/http" $VERBOSE = nil

    EM.synchrony do # monkey patch default Socket code to use EventMachine Sockets instead TCPSocket = EventMachine::Synchrony::TCPSocket Net::HTTP.get_print 'www.google.com', '/index.html' EM.stop end
  20. Advanced EventMachine Goliath class Echo < Goliath::API use Goliath::Rack::Tracer #

    log trace statistics use Goliath::Rack::DefaultMimeType # cleanup accepted media types use Goliath::Rack::Render, 'json' # auto-negotiate response format use Goliath::Rack::Params # parse & merge query and body parameters use Goliath::Rack::Heartbeat # respond to /status with 200, OK (monitoring, etc) # If you are using Golaith version <=0.9.1 you need to Goliath::Rack::ValidationError # to prevent the request from remaining open after an error occurs #use Goliath::Rack::ValidationError use Goliath::Rack::Validation::RequestMethod, %w(GET POST) # allow GET and POST requests only use Goliath::Rack::Validation::RequiredParam, {:key => 'echo'} # must provide ?echo= query or body param plugin Goliath::Plugin::Latency # output reactor latency every second def process_request logger.info "Processing request" {response: env.params['echo']} end