Created
February 4, 2014 11:02
-
-
Save siddharthbhagwan/8801680 to your computer and use it in GitHub Desktop.
Sample Implementation of Action Controller Live
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This gist indends to show a sample run of the ActionController Live, included in Rails 4. | |
It also shows some issues faced in the common implementations. This approach is common for implemeting chat systems, and push notifications. | |
Solution to the issue isn't given here, but I've included links to the discussions that deal with the issues in depth. | |
An up and running redis server is a prerequisite for this demo. | |
To understand and analyze this scenario, it would be helpful to monitor Redis as well. This can be done by running the following two commands in the shell | |
redis-cli | |
monitor | |
The gist shows how 2 clients, in this case, Chrome and Firefox are listenting on the servers for data. On pushing data to redis with the appropriate handlers, data should be alerted on the respecive browsers. For instance, in the rails console | |
redis_conn = Redis.new # makes a default connection on localhost, port 6379 | |
redis_conn.publish('listener_ff', 'Data for Firefox!') | |
This can also be done via a controller action specified for each browser. | |
Refreshing this page 5 times (in my case, or whatever is the max connection pool) leads the server to hang, as the connections have been maxed out. | |
You can try this with threading as well ( just uncomment the code ), and with unicorn server as well ( current is Puma, WebBrick won't work as it buffers the data and sends it in one go ) | |
Below are links that should help you better udnerstand the Action Controller Live | |
http://tenderlovemaking.com/2012/07/30/is-it-live.html | |
https://github.com/rails/rails/issues/10989 | |
Some hacks to this connection issues are using a poker/heartbeat. | |
Using an evented server should solve the issue altogether. | |
Havent tried it yet, but cramp is one such example - http://cramp.in/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
config.cache_classes = true | |
config.eager_load = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
source 'https://rubygems.org' | |
gem 'rails', '4.0.2' | |
gem "redis-rails", "~> 4.0.0" | |
gem 'puma' | |
gem 'unicorn' | |
# Use sqlite3 as the database for Active Record | |
gem 'sqlite3' | |
# Use SCSS for stylesheets | |
gem 'sass-rails', '~> 4.0.0' | |
# Use Uglifier as compressor for JavaScript assets | |
gem 'uglifier', '>= 1.3.0' | |
# Use CoffeeScript for .js.coffee assets and views | |
gem 'coffee-rails', '~> 4.0.0' | |
# Use jquery as the JavaScript library | |
gem 'jquery-rails' | |
# Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks | |
gem 'turbolinks' | |
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder | |
gem 'jbuilder', '~> 1.2' | |
group :doc do | |
# bundle exec rake doc:rails generates the API under doc/api. | |
gem 'sdoc', require: false | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ACL::Application.routes.draw do | |
get 'chrome' => 'sse#sse_chrome' | |
get 'ff' => 'sse#sse_ff' | |
get 'pub_chrome' => 'sse#publish_to_chrome' | |
get 'pub_ff' => 'sse#publish_to_ff' | |
get 'hello' => 'sse#hello' | |
get 'hello_world' => 'sse#hello_world' | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Place all the behaviors and hooks related to the matching controller here. | |
# All this logic will automatically be available in application.js. | |
# You can use CoffeeScript in this file: http://coffeescript.org/ | |
jQuery -> | |
# Check What browser you're running - programmed just to check FF and Chrome | |
browser = window.navigator.userAgent; | |
if browser.indexOf('Chrome') isnt -1 | |
browser_action = 'chrome' | |
else | |
browser_action = 'ff' | |
# Creating handles to listen on, specific to the browser | |
# Assuming Chrome data will be sent on 'listener_chrome' and | |
# Similarly F data on 'listener_ff' | |
event_listener = 'listener_' + browser_action | |
# Event Source is listening on a controller action. Check routes.rb | |
# to see what browser_action is mapped to | |
source = new EventSource(browser_action) | |
source.addEventListener event_listener, (ea) -> | |
alert 'Data for ' + browser_action + ' : ' + ea.data |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class SseController < ApplicationController | |
include ActionController::Live | |
def sse_chrome | |
response.headers["Content-Type"] = "text/event-stream" | |
redis_sub_chrome = Redis.new() | |
subscribe_channel = 'listener_chrome' | |
#Thread.new do | |
redis_sub_chrome.subscribe(subscribe_channel) do |on| | |
on.message do |event, data| | |
response.stream.write("event: #{event}\n") | |
response.stream.write("data: #{data}\n\n") | |
end | |
end | |
#end | |
rescue IOError | |
logger.info "Stream Closed" | |
ensure | |
redis_sub_chrome.quit | |
response.stream.close | |
end | |
# Fn to publish data with handle for the listener on chrome | |
def publish_to_chrome | |
response.headers["Content-Type"] = "text/event-stream" | |
redis_chrome = Redis.new() | |
10.times{ | |
redis_chrome.publish('listener_chrome', 'Data for Chrome!') | |
} | |
render nothing: true | |
end | |
def sse_ff | |
response.headers["Content-Type"] = "text/event-stream" | |
redis_sub_chrome = Redis.new() | |
subscribe_channel = 'listener_ff' | |
#Thread.new do | |
redis_sub_chrome.subscribe(subscribe_channel) do |on| | |
on.message do |event, data| | |
response.stream.write("event: #{event}\n") | |
response.stream.write("data: #{data}\n\n") | |
end | |
end | |
#end | |
rescue IOError | |
logger.info "Stream Closed" | |
ensure | |
redis_sub_chrome.quit | |
response.stream.close | |
end | |
# Fn to publish data with handle for the listener on FireFox | |
def publish_to_ff | |
response.headers["Content-Type"] = "text/event-stream" | |
redis_chrome = Redis.new() | |
10.times{ | |
redis_chrome.publish('listener_ff', 'Data for FF!') | |
} | |
render nothing: true | |
end | |
# Fn to show simple ACL demo | |
def hello_world | |
response.headers['Content-Type'] = 'text/event-stream' | |
10.times do |i| | |
response.stream.write "hello world #{i}\n" | |
sleep 1 | |
end | |
response.stream.close | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment