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

Using RethinkDB with Tornado & EventMachine

Using RethinkDB with Tornado & EventMachine

This talk demonstrates how to use the Tornado and EventMachine integration in RethinkDB's Python and Ruby drivers. It also shows how to build realtime apps in Ruby with RethinkDB and Faye.

Ryan Paul

March 30, 2015
Tweet

More Decks by Ryan Paul

Other Decks in Programming

Transcript

  1. RethinkDB
    Tornado & Event Machine

    View Slide

  2. Ryan Paul
    RethinkDB
    Evangelist
    @segphault

    View Slide

  3. Introduction
    What is RethinkDB?

    View Slide

  4. What is RethinkDB?
    • Open source database for building
    realtime web applications
    • NoSQL database that
    stores schemaless JSON documents
    • Distributed database that is easy to
    scale

    View Slide

  5. Built for Realtime Apps
    • Subscribe to change notifications
    from database queries
    • No more polling — the database
    pushes changes to your app
    • Reduce the amount of plumbing
    needed to stream live updates

    View Slide

  6. Subscribe to change notifications
    on database queries
    Changefeeds

    View Slide

  7. r.table("users").changes()
    Changefeeds
    Track changes on the users table

    View Slide

  8. Changefeeds
    • The changes command returns a
    cursor that receives updates
    • Each update includes the new and
    old value of the modified record

    View Slide

  9. Changefeeds
    r.table("users")
    .filter({name: "Bob"}).delete()
    Changefeed output:
    {
    new_val: null,
    old_val: {
    id: '362ae837-2e29-4695-adef-4fa415138f90',
    name: 'Bob',
    ...
    }
    }

    View Slide

  10. Changefeeds
    r.table("players")
    .orderBy({index: r.desc("score")})
    .limit(3).changes()
    Track top three players by score
    Chain the changes command
    to an actual ReQL query:

    View Slide

  11. Async Frameworks
    Tornado & EventMachine

    View Slide

  12. Async Web Frameworks
    Tornado
    EventMachine

    View Slide

  13. Async Web Frameworks
    • Event-driven programming
    • Non-blocking network I/O
    • Well-suited for the realtime Web

    View Slide

  14. Async Web Frameworks
    • New in RethinkDB 2.0 Python &
    Ruby drivers
    • Download the release candidate
    today
    • Official release coming in April

    View Slide

  15. Async Web Frameworks
    • Perform queries asynchronously
    • Consume multiple changefeeds at
    the same time without blocking

    View Slide

  16. Tornado
    import rethinkdb as r
    from tornado import ioloop, gen
    r.set_loop_type("tornado")
    @gen.coroutine
    def print_changes():
    conn = yield r.connect(host="localhost", port=28015)
    feed = yield r.table("table").changes().run(conn)
    while (yield feed.fetch_next())
    change = yield feed.next()
    print(change)
    ioloop.IOLoop.current().add_callback(print_changes)

    View Slide

  17. Tornado
    import rethinkdb as r
    from tornado import ioloop, gen
    r.set_loop_type("tornado")
    @gen.coroutine
    def print_changes():
    conn = yield r.connect(host="localhost", port=28015)
    feed = yield r.table("table").changes().run(conn)
    while (yield feed.fetch_next())
    change = yield feed.next()
    print(change)
    ioloop.IOLoop.current().add_callback(print_changes)
    Configure the event loop

    View Slide

  18. Tornado
    import rethinkdb as r
    from tornado import ioloop, gen
    r.set_loop_type("tornado")
    @gen.coroutine
    def print_changes():
    conn = yield r.connect(host="localhost", port=28015)
    feed = yield r.table("table").changes().run(conn)
    while (yield feed.fetch_next())
    change = yield feed.next()
    print(change)
    ioloop.IOLoop.current().add_callback(print_changes)
    Add the coroutine decorator

    View Slide

  19. Tornado
    import rethinkdb as r
    from tornado import ioloop, gen
    r.set_loop_type("tornado")
    @gen.coroutine
    def print_changes():
    conn = yield r.connect(host="localhost", port=28015)
    feed = yield r.table("table").changes().run(conn)
    while (yield feed.fetch_next())
    change = yield feed.next()
    print(change)
    ioloop.IOLoop.current().add_callback(print_changes)
    Connect to the database

    View Slide

  20. Tornado
    import rethinkdb as r
    from tornado import ioloop, gen
    r.set_loop_type("tornado")
    @gen.coroutine
    def print_changes():
    conn = yield r.connect(host="localhost", port=28015)
    feed = yield r.table("table").changes().run(conn)
    while (yield feed.fetch_next())
    change = yield feed.next()
    print(change)
    ioloop.IOLoop.current().add_callback(print_changes)
    Perform the ReQL query

    View Slide

  21. Tornado
    import rethinkdb as r
    from tornado import ioloop, gen
    r.set_loop_type("tornado")
    @gen.coroutine
    def print_changes():
    conn = yield r.connect(host="localhost", port=28015)
    feed = yield r.table("table").changes().run(conn)
    while (yield feed.fetch_next())
    change = yield feed.next()
    print(change)
    ioloop.IOLoop.current().add_callback(print_changes)
    Iterate over changefeed changes

    View Slide

  22. Tornado
    import rethinkdb as r
    from tornado import ioloop, gen
    r.set_loop_type("tornado")
    @gen.coroutine
    def print_changes():
    conn = yield r.connect(host="localhost", port=28015)
    feed = yield r.table("table").changes().run(conn)
    while (yield feed.fetch_next())
    change = yield feed.next()
    print(change)
    ioloop.IOLoop.current().add_callback(print_changes)
    Fetch the latest change

    View Slide

  23. Tornado
    import rethinkdb as r
    from tornado import ioloop, gen
    r.set_loop_type("tornado")
    @gen.coroutine
    def print_changes():
    conn = yield r.connect(host="localhost", port=28015)
    feed = yield r.table("table").changes().run(conn)
    while (yield feed.fetch_next())
    change = yield feed.next()
    print(change)
    ioloop.IOLoop.current().add_callback(print_changes)
    Print the change to stdout

    View Slide

  24. Tornado
    import rethinkdb as r
    from tornado import ioloop, gen
    r.set_loop_type("tornado")
    @gen.coroutine
    def print_changes():
    conn = yield r.connect(host="localhost", port=28015)
    feed = yield r.table("table").changes().run(conn)
    while (yield feed.fetch_next())
    change = yield feed.next()
    print(change)
    ioloop.IOLoop.current().add_callback(print_changes)
    Run coroutine in the background

    View Slide

  25. EventMachine
    require "rethinkdb"
    include RethinkDB::Shortcuts
    conn = r.connect host: "localhost", port: 28015
    EM.run do
    r.table("table").changes.em_run(conn) do |err, change|
    puts change
    end
    end

    View Slide

  26. EventMachine
    require "rethinkdb"
    include RethinkDB::Shortcuts
    conn = r.connect host: "localhost", port: 28015
    EM.run do
    r.table("table").changes.em_run(conn) do |err, change|
    puts change
    end
    end
    Connect to the database

    View Slide

  27. EventMachine
    require "rethinkdb"
    include RethinkDB::Shortcuts
    conn = r.connect host: "localhost", port: 28015
    EM.run do
    r.table("table").changes.em_run(conn) do |err, change|
    puts change
    end
    end
    Create an EventMachine block

    View Slide

  28. EventMachine
    require "rethinkdb"
    include RethinkDB::Shortcuts
    conn = r.connect host: "localhost", port: 28015
    EM.run do
    r.table("table").changes.em_run(conn) do |err, change|
    puts change
    end
    end
    Perform the ReQL query

    View Slide

  29. EventMachine
    require "rethinkdb"
    include RethinkDB::Shortcuts
    conn = r.connect host: "localhost", port: 28015
    EM.run do
    r.table("table").changes.em_run(conn) do |err, change|
    puts change
    end
    end
    Print the change to stdout

    View Slide

  30. Building Web Apps
    Realtime Ruby app with Faye

    View Slide

  31. Faye Framework
    • Open source pub/sub framework
    for realtime messaging
    • Communication between
    frontend and backend
    • Supports Ruby and Node.js on the
    backend

    View Slide

  32. Faye Framework
    EM.run do
    ...
    App = Faye::RackAdapter.new Sinatra::Application,
    mount: "/faye"
    conn = r.connect host: "localhost", port: 28015
    r.table("todo").changes.em_run(conn) do |err, change|
    App.get_client.publish("/todo/update", change)
    end
    ...
    end
    Server-side Ruby code

    View Slide

  33. Faye Framework
    EM.run do
    ...
    App = Faye::RackAdapter.new Sinatra::Application,
    mount: "/faye"
    conn = r.connect host: "localhost", port: 28015
    r.table("todo").changes.em_run(conn) do |err, change|
    App.get_client.publish("/todo/update", change)
    end
    ...
    end
    Initialize Faye and bind URL route

    View Slide

  34. Faye Framework
    EM.run do
    ...
    App = Faye::RackAdapter.new Sinatra::Application,
    mount: "/faye"
    conn = r.connect host: "localhost", port: 28015
    r.table("todo").changes.em_run(conn) do |err, change|
    App.get_client.publish("/todo/update", change)
    end
    ...
    end
    Connect to the database

    View Slide

  35. Faye Framework
    EM.run do
    ...
    App = Faye::RackAdapter.new Sinatra::Application,
    mount: "/faye"
    conn = r.connect host: "localhost", port: 28015
    r.table("todo").changes.em_run(conn) do |err, change|
    App.get_client.publish("/todo/update", change)
    end
    ...
    end
    Perform the ReQL query

    View Slide

  36. Faye Framework
    EM.run do
    ...
    App = Faye::RackAdapter.new Sinatra::Application,
    mount: "/faye"
    conn = r.connect host: "localhost", port: 28015
    r.table("todo").changes.em_run(conn) do |err, change|
    App.get_client.publish("/todo/update", change)
    end
    ...
    end
    Publish the update to a channel

    View Slide

  37. Faye Framework
    faye.subscribe("/todo/update", function(data) {
    console.log(data);
    });
    Client-side JavaScript code

    View Slide

  38. DEMO

    View Slide