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
45
Building Upworthy on Rails
luigi
1
140
You'll Never Believe Which Web Framework Powers Upworthy
luigi
0
10k
Server-Sent Events at Realtime Conf 2012
luigi
4
500
Developer Happiness & MongoDB
luigi
2
480
Other Decks in Programming
See All in Programming
Software Architecture
hschwentner
6
2.1k
Flutter × Firebase Genkit で加速する生成 AI アプリ開発
coborinai
0
150
『GO』アプリ データ基盤のログ収集システムコスト削減
mot_techtalk
0
110
社内フレームワークとその依存性解決 / in-house framework and its dependency management
vvakame
1
550
昭和の職場からアジャイルの世界へ
kumagoro95
1
350
『品質』という言葉が嫌いな理由
korimu
0
160
2,500万ユーザーを支えるSREチームの6年間のスクラムのカイゼン
honmarkhunt
6
5.1k
個人アプリを2年ぶりにアプデしたから褒めて / I just updated my personal app, praise me!
lovee
0
340
TokyoR116_BeginnersSession1_環境構築
kotatyamtema
0
110
SwiftUI Viewの責務分離
elmetal
PRO
0
140
知られざるDMMデータエンジニアの生態 〜かつてツチノコと呼ばれし者〜
takaha4k
4
1.3k
Kubernetes History Inspector(KHI)を触ってみた
bells17
0
200
Featured
See All Featured
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
20
2.4k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
248
1.3M
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
29
2.2k
Building Better People: How to give real-time feedback that sticks.
wjessup
366
19k
Side Projects
sachag
452
42k
It's Worth the Effort
3n
184
28k
Optimising Largest Contentful Paint
csswizardry
34
3.1k
How to train your dragon (web standard)
notwaldorf
90
5.8k
Build your cross-platform service in a week with App Engine
jlugia
229
18k
Fashionably flexible responsive web design (full day workshop)
malarkey
406
66k
Rebuilding a faster, lazier Slack
samanthasiow
79
8.8k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
132
33k
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?