Goliath

et ses amis

  • Rack
  • Fiber
  • EventMachine
  • EM-Synchrony

Bruno Michel

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

Fast Food

1 thread par connexion

Credit Card

Modèle événementiel

Japonais

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

  1. Pas prêt
  2. 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

  1. Callbacks avec de nombreuses indentations
  2. Callbacks nommés, mais avec de nombreux arguments
  3. 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 runner et 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