Goliath
et ses amis
- Rack
- Fiber
- EventMachine
- EM-Synchrony
Bruno Michel
- Lead Dev chez af83
- Développeur de LinuxFr.org
- Membre actif de Ruby France
- github.com/nono
- twitter.com/brmichel
Rack : la spec
A Rack application is an Ruby object (not a class) that responds to call. It takes exactly one argument, the environment and returns an Array of exactly three values: The status, the headers, and the body.
Rack : un exemple
class HelloWorld
def call(env)
[200,
{"Content-Type" => "text/plain"},
["Hello World!"]]
end
end
Rack : les middlewares
Rack::Builder.new do
use Rack::CommonLogger
use Rack::ShowExceptions
use Rack::Head
use Rack::Lint
run HelloWorld.new
end
Rack : les middlewares
app = HelloWorld.new
app = Rack::Lint.new(app)
app = Rack::Head.new(app)
app = Rack::ShowExceptions.new(app)
app = Rack::CommonLogger.new(app)
Rack : exemple de middleware
class Rack::Head
def initialize(app)
@app = app
end
def call(env)
status, headers, body = @app.call(env)
body = [] if env["REQUEST_METHOD"] == "HEAD"
[status, headers, body]
end
end
Rack et Goliath
require "goliath"
class Hello < Goliath::API
use Rack::ContentLength
def response(env)
[200, {}, "Hello World!"]
end
end
EventMachine
- Framework Ruby
- Evented
- Des drivers réseaux
- (http, mysql, redis, MongoDB, SMTP, AMQP, XMPP and many more)
1 processus par connexion

1 thread par connexion

Modèle événementiel

EventMachine : Exemple
#!/usr/bin/env ruby
require 'eventmachine'
EM.run do
EM.add_periodic_timer(1) { puts "Tick ..." }
EM.add_timer(5) { EM.stop_event_loop }
end
puts "Fini"
Goliath et EventMachine
class Stream < Goliath::API
def response(env)
i = 0
pt = EM.add_periodic_timer(1) do
env.stream_send("#{i += 1} ")
end
EM.add_timer(10) do
pt.cancel
env.stream_close
end
[200, {}, Goliath::Response::STREAMING]
end
end
Node.js
/!\ Attention /!\
Ça va troller...
Node.js : défauts
- Pas prêt
- Code difficile à relire
Node.js : pas prêt
- Manque de bibliothèque standard
- (base64, yaml, logging, mails)
- API pas stable
- Memory leaks
- Toujours pas de Webworkers
Node.js : code illisible
- Callbacks avec de nombreuses indentations
- Callbacks nommés, mais avec de nombreux arguments
- Passer les arguments avec
this
=> Code difficile à tester
Ruby 1.9 et les fibres
def async_fetch(url)
f = Fiber.current
http = EM::HttpRequest.new(url).get :timeout => 10
http.callback { f.resume(http) }
http.errback { f.resume(http) }
return Fiber.yield
end
EM.run do
Fiber.new {
data = async_fetch('http://www.google.com/')
puts "Fetched page #1: #{data.response_header.status}"
EM.stop
}.resume
end
EM-Synchrony : exemple
EM.synchrony do
multi = EM::Synchrony::Multi.new
multi.add :page1, EM::HttpRequest.new("http://service.com/page1").aget
multi.add :page2, EM::HttpRequest.new("http://service.com/page2").aget
multi.add :page3, EM::HttpRequest.new("http://service.com/page3").aget
data = multi.perform.responses[:callback].values
end
EM-Synchrony : exemple (suite)
EM.synchrony do
data = ["Données de l'exemple précédent"]
db = EM::Synchrony::ConnectionPool.new(size: 4) do
EM::MySQL.new(host: "localhost")
end
EM::Synchrony::Iterator.new(data, 2).each do |page, iter|
db.aquery("INSERT INTO table (data) VALUES(#{page});")
db.callback { iter.return(http) }
end
end
Goliath et EM-Synchrony
require 'goliath'
require 'em-synchrony/em-http'
class HelloWorld < Goliath::API
def response(env)
req = EM::HttpRequest.new("http://www.google.com/").get
resp = req.response
[200, {}, resp]
end
end
Goliath : le reste
- Plusieurs modes : dev / test / prod
- Configuration par environnement
- Les plugins : du code EventMachine
- Le
runneret ses options - ...
Goliath : le futur
- Cloud Foundry
- Websockets (en cours)
- SPDY ?
- Interface à la Sinatra/Grape ?
Goliath
Conclusion
That's all folks
Questions ?
Credits
- http://www.flickr.com/photos/consumerist/614672919/
- http://www.flickr.com/photos/nzbuu/3314624297/
- http://www.flickr.com/photos/wakelucid/4760639193/
Slides on github.com/nono/Presentations