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.

Ba70f10866cbab0bc6b9b1d547ef8015?s=128

Ryan Paul

March 30, 2015
Tweet

Transcript

  1. RethinkDB Tornado & Event Machine

  2. Ryan Paul RethinkDB Evangelist @segphault

  3. Introduction What is RethinkDB?

  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
  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
  6. Subscribe to change notifications on database queries Changefeeds

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

  8. Changefeeds • The changes command returns a cursor that receives

    updates • Each update includes the new and old value of the modified record
  9. Changefeeds r.table("users") .filter({name: "Bob"}).delete() Changefeed output: { new_val: null, old_val:

    { id: '362ae837-2e29-4695-adef-4fa415138f90', name: 'Bob', ... } }
  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:
  11. Async Frameworks Tornado & EventMachine

  12. Async Web Frameworks Tornado EventMachine

  13. Async Web Frameworks • Event-driven programming • Non-blocking network I/O

    • Well-suited for the realtime Web
  14. Async Web Frameworks • New in RethinkDB 2.0 Python &

    Ruby drivers • Download the release candidate today • Official release coming in April
  15. Async Web Frameworks • Perform queries asynchronously • Consume multiple

    changefeeds at the same time without blocking
  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)
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  30. Building Web Apps Realtime Ruby app with Faye

  31. Faye Framework • Open source pub/sub framework for realtime messaging

    • Communication between frontend and backend • Supports Ruby and Node.js on the backend
  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
  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
  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
  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
  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
  37. Faye Framework faye.subscribe("/todo/update", function(data) { console.log(data); }); Client-side JavaScript code

  38. DEMO