Type a keyword and hit enter to start searching. Press Esc to cancel.

Currently Reading

Shower: A Redis Based Pub/Sub Message Streaming Solution For Rails 4

Shower is a gem for Ruby on Rails 4 that simplifies message streaming, the ability to push data to the front end in real time.  ActionController::Live is a new feature in Rails 4 that allows for message streaming.  Essentially, a user opens a persistent connection to a Live controller and messages are pushed through the connection.  While instant messaging seems to be the standard ‘Hello World’ introduction to streaming, there are many more uses.  For example, inventory notifications for an online store, stock prices, breaking news, maintenance alerts, etc.  As message streaming finds more uses, more and more clients will expect to see those features in their sites and applications.

Basic Example

To take advantage of this great technology using Shower, you only need to write 5 lines of code in 3 simple steps.

1. Subscribe to message stream events.  In this case, we will listen to the alert.new event, but you can pass an array of as many events as you wish.

stream = new Shower('/stream', ['alert.new'])

2. Define an event to take place when a message is received.  In this case, we will simply open a JavaScript alert with the event data.

stream.addEventListener('alert.new', function(event) {
  return alert(event.data);
});

3. Publish an event to the message stream.

Shower::Stream.publish('alert.new', 'Hello World!')

It’s that simple!

JSON Data Example

Let’s look at another quick example which demonstrates the ability to push JSON objects.

1. Subscribe to the message.new event stream.

stream = new Shower('/stream', ['message.new'])

2. When there is a new message, create an alert showing who the message is from and the actual message.

stream.addEventListener('message.new', function(event) {
  return alert("Message From:" + event.data.username + " - " + event.data.message);
});

3. Publish a message.

Shower::Stream.publish('message.new', { username: 'anon', message: 'hello!' })

Controller Breakdown

To explain how this all works, let’s look at the StreamController:

class Shower::StreamController < ApplicationController
    include ActionController::Live

    before_action :close_db_connection

    def index
      response.headers['Content-Type'] = 'text/event-stream'
      redis = Redis.new

      redis.subscribe(params[:events].split(',') << 'heartbeat') do |on|
        on.message do |event, data|
          response.stream.write("event: #{event}\n")
          response.stream.write("data: #{data}\n\n")
        end
      end
    rescue IOError
      # stream closed
    ensure
      # stopping stream thread
      redis.quit
      response.stream.close
    end

    private

    def close_db_connection
      ActiveRecord::Base.connection_pool.release_connection
    end

end

He’s a brief synopsis of what’s going on:

  • include ActionController::Live allows us to open the event stream.
  • before_action :close_db_connection, this will close the current database connection, so we aren’t using up any of our available connections from the database pool.  This is especially important once you have few dozen connections open.
  • At the beginning of the index action, we declare the text/event-stream content type headers.  This lets the other side know that there are going to be event messages streaming through, so the connection should be left open.
  • Then we create a new Redis instance and subscribe the user to the their requested events, plus the heartbeat
    • The heartbeat is a way of destroying stale connections.
  • Then when the redis instance pickups up on any of the subscribed events, we write them to the stream.  First the event name is written, then the event data.
  • Finally, we ensure that the redis instance is destroyed and the stream is closed.

If you would like to know more about how Shower works, feel free to poke around the repository.  If you think it can be improved, fork it and create a pull request.

https://github.com/kpheasey/shower

 

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *