An example Rails app which uses RethinkDB + NodeJS microservice to push background operation progress to the front-end. The progress is updated in the DB via NoBrainer ORM, and RethinkDB's changefeed is delivered to the front-end using Server-Sent Events (SSE) and rendered in the UI with RiotJS.
The Ruby part of this example can be deployed to Heroku with the standard Git deployment flow.
Once deployed, set RETHINKDB_PASSWORD
heroku config var to something random
heroku config:set RETHINKDB_PASSWORD="some-random-secret-582"
Setting up RethinkDB + NodeJS microservice at Heroku can be done via Dockhero addon (see docs ). Please sign up for free alpha access at dockhero.io
heroku plugins:install dockhero
heroku addons:create dockhero
heroku dh:wait
heroku dh:compose up -d
Now everything should be up and running, and you can test the app:
heroku open
In this example all the "magic" is happening in livestatus/server.js
file,
which acts as a "cable" between the Ruby-on-Rails back-end and RiotJS front-end.
It streams a sequence of changes from RethinkDB database to front-end via SSE.
// livestatus/server.js
app.use(rethinkSse()) // a middleware which renders an SSE stream from RethinkDB's cursor
app.use(route.get("/operations/:id", function *(id) {
const cursor = yield r.table("operations")
.get(id)
.changes({include_initial: true})
.run(this._rdbConn);
this.rethinkSse(cursor);
}));
On the Rails back-end, the changes are initiated with the following code in WelcomeController
which updates an instance of Operation record in RethinkDB
# app/controllers/welcome_controller.rb
def do_something
operation.progress += 1
operation.save!
render json: {status: 'OK'}
end
On the client, the SSE stream is consumed in app/assets/javascripts/progressor.tag
using Rx.DOM.fromEventSource
RxJS extension.
// app/assets/javascripts/progressor.tag
var source = Rx.DOM.fromEventSource(opts.feed_url).map(function(data) {
return JSON.parse(data);
});
var subscription = source.subscribe(function(data) {
this.update({progress: data.progress})
}.bind(this));