Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Real-Time HTML5 and Ruby
Search
Luigi Ray-Montanez
March 24, 2012
Programming
3
650
Real-Time HTML5 and Ruby
Presented at RubyNation on March 24, 2012.
Luigi Ray-Montanez
March 24, 2012
Tweet
Share
More Decks by Luigi Ray-Montanez
See All by Luigi Ray-Montanez
A Decade under the Influence
luigi
0
49
Building Upworthy on Rails
luigi
1
160
You'll Never Believe Which Web Framework Powers Upworthy
luigi
0
11k
Server-Sent Events at Realtime Conf 2012
luigi
4
530
Developer Happiness & MongoDB
luigi
2
480
Other Decks in Programming
See All in Programming
ニーリーにおけるプロダクトエンジニア
nealle
0
470
Select API from Kotlin Coroutine
jmatsu
1
190
Deep Dive into ~/.claude/projects
hiragram
8
1.5k
『自分のデータだけ見せたい!』を叶える──Laravel × Casbin で複雑権限をスッキリ解きほぐす 25 分
akitotsukahara
1
540
Blazing Fast UI Development with Compose Hot Reload (droidcon New York 2025)
zsmb
1
210
地方に住むエンジニアの残酷な現実とキャリア論
ichimichi
5
1.3k
Java on Azure で LangGraph!
kohei3110
0
170
iOSアプリ開発で 関数型プログラミングを実現する The Composable Architectureの紹介
yimajo
2
210
Cursor AI Agentと伴走する アプリケーションの高速リプレイス
daisuketakeda
1
130
なんとなくわかった気になるブロックテーマ入門/contents.nagoya 2025 6.28
chiilog
1
210
GoのGenericsによるslice操作との付き合い方
syumai
3
690
Webの外へ飛び出せ NativePHPが切り拓くPHPの未来
takuyakatsusa
2
360
Featured
See All Featured
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
16k
Unsuck your backbone
ammeep
671
58k
Facilitating Awesome Meetings
lara
54
6.4k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
3.9k
4 Signs Your Business is Dying
shpigford
184
22k
Product Roadmaps are Hard
iamctodd
PRO
54
11k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
130
19k
The Power of CSS Pseudo Elements
geoffreycrofte
77
5.8k
RailsConf 2023
tenderlove
30
1.1k
StorybookのUI Testing Handbookを読んだ
zakiyama
30
5.8k
Side Projects
sachag
455
42k
Site-Speed That Sticks
csswizardry
10
660
Transcript
Real-Time HTML5 and Ruby Luigi Montanez RubyNation 2012
Overview Part 1 - Real-time HTML5 Technologies Part 2 -
EventMachine Part 3 - Ruby frameworks
tl;dw You can do this stu! in Ruby, you don’t
need Node.js.
Part 1: Real-Time HTML5 Technologies
The Enemy: Page Refreshing
“Classic” Solutions AJAX AJAX Polling COMET (Long Polling)
“Classic” Solutions AJAX AJAX Polling COMET (Long Polling)
WebSockets TCP Socket between browser and server Bi-directional Remains open
until explicitly closed
In the Browser var connection = new WebSocket('ws://example.com/echo'); connection.onopen =
function () { connection.send('Ping'); }; connection.onerror = function (error) { // handle error }; connection.onmessage = function (e) { console.log('Server said: ' + e.data); }; connection.onclose = function () { // ensure you expected a close };
Just TCP A lower level than HTTP Developer de"nes protocol
Support XMPP, IRC, AMQP, VNC Some proxy servers not compatible
No JS Poly!ll Flash-based fallback Socket.IO falls back using di!erent
methods
Bi-directional communication usually overkill.
Server-Sent Events Forgotten little brother of WebSockets Downstream, server to
browser push Just HTTP Browser handles reconnections Pure JS Poly"ll by Remy Sharp
In the Browser var source = new EventSource('/stream'); source.addEventListener('message', function(e)
{ console.log(e.data); }); source.addEventListener('open', function(e) { ... }); source.addEventListener('error', function(e) { ... });
Data data: first line\n data: second line\n\n --- data: {\n
data: "msg": "hello world",\n data: "id": 12345\n data: }\n\n source.addEventListener('message', function(e) { var data = JSON.parse(e.data); console.log(data.id, data.msg); });
Data IDs and Events id: 12345\n data: AAPL\n data: 572.44\n\n
--- data: {"msg": "First message"}\n\n event: userlogon\n data: {"username": "John123"}\n\n event: update\n data: {"username": "John123", "emotion": "happy"}\n\n source.addEventListener('userlogon', function(e) { ... source.addEventListener('update', function(e) { ...
Part 2: EventMachine
Why EM? Many concurrent, long-held connections Addresses the C10K Problem
Can’t use Rails or Rack to support WebSockets and Server-Sent Events
Reactor Pattern Single-threaded event loop listens to many sources Dispatches
synchronous work to handlers Handlers report when done
Timebomb require 'eventmachine' EM.run do EM.add_timer(5) do puts "BOOM" EM.stop_event_loop
end EM.add_periodic_timer(1) do puts "Tick" end end $ ruby timer.rb Tick Tick Tick Tick BOOM
Other Constructs EM#next_tick EM#defer EM::Deferrable EM::Queue EM::Channel
Problem: Pyramid Code or Callback Spaghetti
Tip of the Pyramid EventMachine.run { page = EventMachine::HttpRequest.new('http://example.com/').get page.errback
{ p "Google is down! terminate?" } page.callback { about = EventMachine::HttpRequest.new('http://example2.com').get about.callback { # callback nesting, ad infinitum } about.errback { # error-handling code } } }
EM::Synchrony Ruby 1.9 Fibers Abstracts away callbacks and errbacks Code
looks synchronous but is actually asynchronous
EM + Fiber def http_get(url) f = Fiber.current http =
EM::HttpRequest.new(url).get # resume fiber once http call is done http.callback { f.resume(http) } http.errback { f.resume(http) } return Fiber.yield end EM.run do Fiber.new{ page = http_get('http://www.google.com/') puts "Fetched page: #{page.response_header.status}" if page page = http_get('http://www.google.com/search?q=eventmachine') puts "Fetched page 2: #{page.response_header.status}" end }.resume end
EM::Synchrony::Multi EventMachine.synchrony do multi = EventMachine::Synchrony::Multi.new multi.add :a, EventMachine::HttpRequest.new(uri1).aget multi.add
:b, EventMachine::HttpRequest.new(uri2).apost multi.add :c, EventMachine::HttpRequest.new(uri3).aget res = multi.perform p "Look ma, no callbacks, and parallel HTTP requests!" p res EventMachine.stop end
Part 3: Ruby Frameworks
All built on top of EventMachine
Servers Thin Rainbows!
Cramp Built by Pratik Naik, “lifo” http://cramp.in Supports Fibers $
cramp new myapp
Server-Sent Events class TimeAction < Cramp::Action self.transport = :sse on_start
:send_latest_time periodic_timer :send_latest_time, :every => 2 def send_latest_time data = {'time' => Time.now.to_i}.to_json render data end end
Goliath Built by Ilya Grigorik http://goliath.io Supports EM::Synchrony Both a
server and a framework
Goliath App class Websocket < Goliath::API use Goliath::Rack::Favicon, ‘favicon.ico') map
'/ws', WebsocketEndPoint end
WebSocket Endpoint class WebsocketEndPoint < Goliath::WebSocket def on_open(env) env.logger.info("WS OPEN")
env['subscription'] = env.channel.subscribe { |m| env.stream_send(m) } end def on_message(env, msg) env.logger.info("WS MESSAGE: #{msg}") env.channel << msg end def on_close(env) env.logger.info("WS CLOSED") env.channel.unsubscribe(env['subscription']) end def on_error(env, error) env.logger.error error end end
Frameworks AsyncRack Cramp Faye::WebSocket Goliath
Caveats Separate app Ports vs. Paths Automated Testing
Credits HTML5 Rocks Ilya Grigorik Dan Sinclair Peepcode
Questions?