Rack
-
Upload
shen-liu -
Category
Technology
-
view
3.406 -
download
0
description
Transcript of Rack
Rack
孟 岩
Elan Meng
Caibangzi.com
IN-SRC Studio
Thanks !!
Rack Sales?
Overview
• Why Rack
• What’s Rack
• Rack Middleware
• Rails on Rack
• Example
• Q & A
Problems
• Ruby is popular
• Different web servers (app servers)
• Different web frameworks
• each framework has to write it’s own handlers to different web servers
• Not only the handler
We hate duplication!
How?
AbstractionInterface
make the simplest possible API that
represents a generic web application
Request -> Response
Request• CGI Envrionment
• {"HTTP_USER_AGENT"=>"curl/7.12.2 ..." "REMOTE_HOST"=>"127.0.0.1", "PATH_INFO"=>"/", "HTTP_HOST"=>"ruby-lang.org", "SERVER_PROTOCOL"=>"HTTP/1.1", "SCRIPT_NAME"=>"", "REQUEST_PATH"=>"/", "REMOTE_ADDR"=>"127.0.0.1", "HTTP_VERSION"=>"HTTP/1.1", "REQUEST_URI"=>"http://ruby-lang.org/", "SERVER_PORT"=>"80", "HTTP_PRAGMA"=>"no-cache", "QUERY_STRING"=>"", "GATEWAY_INTERFACE"=>"CGI/1.1", "HTTP_ACCEPT"=>"*/*", "REQUEST_METHOD"=>"GET"}
ResponseHTTP/1.1 302
Found Date: Sat, 27 Oct 2007 10:07:53 GMT Server: Apache/2.0.54 (Debian GNU/Linux)mod_ssl/2.0.54 OpenSSL/0.9.7e Location: http://www.ruby-lang.org/ Content-Length: 209 Content-Type: text/html; charset=iso-8859-1
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"><html><head> <title>302 Found</title> </head><body> <h1>Found</h1> <p>The document has moved <ahref="http://www.ruby-lang.org/">here</a>.</p> </body></html>
What’s Rack• Duck-Type
• Ruby object that respond_to? :call
• One argument, the environment variable
• return values
• status - respond_to? :to_i
• headers - respond_to? :each, yield key/value
• body - respond_to? :each, yield string
lambda { |env| [ 200, {'Content-Type' => 'text/plain', 'Content-Length' => '16'}, ["Beijing on Rails"] ]}
app = lambda { |env| [ 200, {'Content-Type' => 'text/plain', 'Content-Length' => ’16’}, ["Beijing on Rails"] ]}
run app
rackup config.ru
Beijing on Rails
%w(rubygems rack).each { |dep| require dep } Rack::Handler::Mongrel.run(app, :Port => 3000)
Rack Middleware
HTTPFramework
APP
Rack Middleware
HTTPFramework
APP
Rack
module Rack class BeijingOnRails def initialize(app) @app = app end
def call(env)... ...status, headers body = @app.call(env)... ...
[status, header, body] end endend
app = Rack::CommonLogger.new( Rack::ShowExceptions.new(
Rack::ShowStatus.new( Rack::Lint.new(app))))
Rack Middleware
HTTPFramework
APP
Middleware
Rack Middleware
• Chain of Responsibilities
app = Rack::CommonLogger.new( Rack::ShowExceptions.new(
Rack::ShowStatus.new( Rack::Lint.new(app))))
Rack Distribution
• Specification
• Handlers
• Adapters
• Middlewares
• Utilities
Rack - Specification
• Rack::Lint
specify "notices status errors" do lambda { Rack::Lint.new(lambda { |env| ["cc", {}, ""] }).call(env({})) }.should.raise(Rack::Lint::LintError). message.should.match(/must be >=100 seen as integer/)
lambda { Rack::Lint.new(lambda { |env| [42, {}, ""] }).call(env({})) }.should.raise(Rack::Lint::LintError). message.should.match(/must be >=100 seen as integer/) end
Rack - Handlers
• CGI
• FastCGI
• Mongrel
• WEBrick
• Thin
• Passenger
• Unicorn
Rack - Adapters
• Camping
• Merb
• Rails
• Sinatra
• ......
Rack - Middleware
• Rack::Static & Rack::File
• Rack::CommonLogger
• Rack::Reloader
• Rack::ShowExceptions
Rack - Utilities
• Rackup
• a useful tool for running Rack applications
• Rackup::Builder
• DSL to configure middleware and build up applications easily
app = Rack::Builder.new do
use Rack::CommonLogger use Rack::ShowExceptions use Rack::ShowStatususe Rack::Lintrun MyRackApp.new
end
Rack::Handler::Mongrel.run app, :Port => 8080
Rails on Rack
The most important change in Rails over the past year - its move to
become Rack-- Ben Scofield
Rails on Rack
• first commit - Ezra & Josh on June 2008
Rails on Rack
• Merb & Rails merge
• ActionController::Dispatcher.new
• ActionController::MiddlewareStack
• ActionController -> Rack Middleware
• ActionDispatch::Failsafe
• ActionDispatch::ShowExceptions
• Plugin -> Rack Middleware
• Hoptoad_notifier plugin -> Rack::Hoptoad.
app = Rack::Builder.new { use Rails::Rack::LogTailer unless options[:detach] use Rails::Rack::Debugger if options[:debugger]
map "/" do use Rails::Rack::Static run ActionController::Dispatcher.new end}.to_app
# RAILS_ROOT/config.rurequire "config/environment"
use Rails::Rack::LogTaileruse Rails::Rack::Staticrun ActionController::Dispatcher.new
rackup
Metal
• bypass some of the normal overhead of the Rails stack
• specify certain routes and code to execute when those routes are hit.
• avoid the entirety of ActionController
• Rails::Rack::Metal
• ActionController::MiddlewareStack
$ script/generate metal poller
class Poller def self.call(env) if env["PATH_INFO"] =~ /^\/poller/ [200, {"Content-Type" => "text/html"}, ["Hello, World!"]] else [404, {"Content-Type" => "text/html"}, ["Not Found"]] end endend
def call(env) @metals.keys.each do |app| result = app.call(env) return result unless result[0].to_i == 404 end @app.call(env)end
Rack::Metal
Response Timer
module Rack class Runtime def initialize(app, name = nil) @app = app @header_name = "X-Runtime" @header_name << "-#{name}" if name end
def call(env) start_time = Time.now status, headers, body = @app.call(env) request_time = Time.now - start_time
if !headers.has_key?(@header_name) headers[@header_name] = "%0.6f" % request_time end
[status, headers, body] end endend
http://github.com/rack/rack-contrib
CodeRack
• http://coderack.org/
• a competition to develop most useful and top quality Rack middlewares.
• 1 DAY LEFT
WRAP UP
Rack is a beautiful thing- Ryan Bates
References
• Introducing Rack - Christian Neukirchen
• http://rack.rubyforge.org/
• RailsCasts 151: Rack Middleware
• http://heroku.com/how/architecture
Q & A
• Rack
• Ruby on Rails
• Caibangzi.com
• Mutual Fund & Investment
Why not simply string
• Ruby 1.8
• String was a collection of bytes
• String’s :each method iterated over lines of data
• Ruby 1.9
• String is now a collection of encoded data. (Raw bytes and encoding information)
• :each has been removed from String and it’s no longer Enumerable