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

Practical EventMachine

febuiles
October 25, 2014

Practical EventMachine

EventMachine (EM) is an event-driven concurrency library for Ruby, akin to Python's Twisted or Node.js. In this talk we'll explore some of the patterns and abstractions behind EM, how we can apply those ideas to our applications and how the library has been used by companies like GitHub and Heroku.

febuiles

October 25, 2014
Tweet

More Decks by febuiles

Other Decks in Programming

Transcript

  1. Practical
    EventMachine

    View Slide

  2. @febuiles

    View Slide

  3. http://goo.gl/Oqe4SI

    View Slide

  4. Events
    events

    View Slide

  5. $("#door").on("open", function(){
    log("We got a new Joe in town...");
    });

    View Slide

  6. WHY EVENTS?

    View Slide

  7. i/o

    View Slide

  8. latency

    View Slide

  9. MOST APPLICATIONS
    ARE I/O BOUND
    I/O BOUND

    View Slide

  10. https://github.com/blog/517-unicorn
    YOUR TYPICAL
    CONCURRENCY
    MODEL

    View Slide

  11. server = TCPServer.new(1337)
    !
    while client = server.accept
    message = client.readline
    client.write "> #{message}"
    client.close
    end

    View Slide

  12. server = TCPServer.new(1337)
    !
    while true
    Thread.new(server.accept) do |client|
    message = client.readline
    client.write "> #{message}"
    client.close
    end
    end

    View Slide

  13. THE REACTOR

    View Slide

  14. What is a reactor?

    View Slide

  15. while true
    events.each do |event|
    event.process
    end
    end

    View Slide

  16. Chernobyl, 1986

    View Slide

  17. New Safe Confinement (NSC)

    View Slide

  18. DON’T BLOCK THE REACTOR

    View Slide

  19. Reactor.run {
    on(:receive) do |msg|
    return if invalid_message(msg)?
    !
    device = Device.find(msg.device_id)
    device.update(position: msg.position)
    end
    }

    View Slide

  20. Reactor.run {
    on(:receive) do |msg|
    return if invalid_message(msg)?
    !
    device = Device.find(msg.device_id)
    device.update(position: msg.position)
    end
    }

    View Slide

  21. What is EventMachine?

    View Slide

  22. EventMachine is an
    event-driven I/O and
    lightweight concurrency
    library for Ruby.

    View Slide

  23. ?

    View Slide

  24. EventMachine is a fast,
    simple event-
    processing library for
    Ruby programs

    View Slide

  25. A PIMPED REACTOR.

    View Slide

  26. Why EventMachine?

    View Slide

  27. EventMachine is dead.

    View Slide

  28. View Slide

  29. EventMachine is dead
    EventMachine is stable.

    View Slide

  30. Heroku
    Thin
    Campfire
    GitHub
    Rainbows
    EngineYard

    View Slide

  31. module Echo
    def receive_data(message)
    send_data "> #{message}"
    end
    end
    !
    EM.run {
    EM.start_server "0.0.0.0", 1337, Echo
    }

    View Slide

  32. module Echo
    def post_init
    puts "Client connected"
    end
    !
    def receive_data(message)
    send_data "> #{message}"
    end
    !
    def unbind
    puts "Client disconnected"
    end
    end
    !
    EM.run {
    EM.start_server "0.0.0.0", 1337, Echo
    }

    View Slide

  33. EM HANDLERS
    VS
    CALLBACK HELL

    View Slide

  34. server = AsyncTCPServer.new("0.0.0.0", 1337)
    !
    server.on(:accept) {
    message = client.async_read
    !
    message.on(:ready) {
    client.write "> #{message}"
    client.close
    }
    }
    !
    server.on(:connect) {
    puts "Client connected"
    }
    !
    server.on(:disconnect) {
    puts "Client disconnected"
    }

    View Slide

  35. events

    post_init
    connection_completed
    receive_data

    unbind
    ssl_handshake_completed
    methods
    start_tls
    get_peername

    send_data

    close_connection
    close_connection_after_writing
    proxy_incoming_to
    pause/resume

    View Slide

  36. Mixing Paradigms

    View Slide

  37. module Echo
    def receive_data(data)
    message = parse_data(data)
    return if invalid_message(message)?
    !
    device = Device.find(message.device_id)
    device.update(position: message.position)
    send_data :updated
    end
    end
    !
    EM.run {
    EM.start_server "0.0.0.0", 1337, Echo
    }

    View Slide

  38. module Echo
    def receive_data(data)
    message = parse_data(data)
    return if invalid_message(message)?
    !
    device = Device.find(message.device_id)
    device.update(position: message.position)
    send_data :updated
    end
    end
    !
    EM.run {
    EM.start_server "0.0.0.0", 1337, Echo
    }

    View Slide

  39. DON’T BLOCK THE REACTOR

    View Slide

  40. View Slide

  41. DATA STORES
    !
    cassandra
    couchdb
    memcached
    mongodb
    mysql
    postgresql
    redis

    View Slide

  42. HTTP
    !
    HttpRequest
    Faraday

    View Slide

  43. PROTOCOLS
    !
    tcp
    udp
    amqp
    smtp
    stomp
    xmpp
    dns
    websockets
    and more…

    View Slide

  44. Other
    !
    EM.popen
    EM.defer

    View Slide

  45. module Graham
    def receive_data(number)
    calculate = proc {
    graham(number)
    }
    !
    report = proc { |result|
    send_data(result)
    }
    !
    EM.defer(calculate, report)
    end
    end

    View Slide

  46. EM API

    View Slide

  47. EM API
    !
    EM::timer
    EM::deferrable
    EM::queue
    EM::channel
    EM.watch_file
    EM.watch_process

    View Slide

  48. Closing Thoughts

    View Slide

  49. Events are hard.

    View Slide

  50. Evented Programming
    for Evented Problems

    View Slide

  51. DON’T
    BLOCK
    THE
    REACTOR
    !!1

    View Slide

  52. Thanks :)
    !
    http://mheroin.com/rubyconfar
    @febuiles

    View Slide

  53. Credits
    Federico’s illustration: Pablo Pérez
    Nuclear cooling tower: Jonathan Brennan
    Some code samples: Aman Gupta & Jeremy Cheung
    Unicorn diagram: GitHub
    The rest: Wikipedia

    View Slide