|
You are here |
peter.michaux.ca | ||
| | | | |
tenderlovemaking.com
|
|
| | | | | TL;DR: Rack API is poor when you consider streaming response bodies. class FooApplication class ErbPage def to_a head = "the head tag" sleep(2) body = "the body tag" sleep(2) [head, body] end end def call(env) [200, {}, ErbPage.new.to_a] end end class FakeRack def serve(application) status, headers, body = application.call({}) p :status => status p :headers => headers body.each do |string| p string end body.close if body.respond_to?(:close) end end app = FooApplication.new rack = FakeRack.new rack.serve app $ time ruby foo.rb {:status=>200} {:headers=>{}} "the head tag" "the body tag" real 0m4.008s user 0m0.003s sys 0m0.003s class ResponseTimer def initialize(app) @app = app end def call(env) now = Time.now status, headers, body = @app.call(env) headers['X-Response-Took'] = Time.now - now [status, headers, body] end end app = FooApplication.new timer = ResponseTimer.new app rack = FakeRack.new rack.serve timer $ time ruby foo.rb {:status=>200} {:headers=>{"X-Response-Took"=>3.999937}} "the head tag" "the body tag" real 0m4.010s user 0m0.004s sys 0m0.004s class FooApplication class ErbPage def each head = "the head tag" yield head sleep(2) body = "the body tag" yield body sleep(2) end end def call(env) [200, {}, ErbPage.new] end end $ time ruby foo.rb {:status=>200} {:headers=>{"X-Response-Took"=>1.1e-05}} "the head tag" "the body tag" real 0m4.032s user 0m0.027s sys 0m0.016s class ResponseTimer def initialize(app) @app = app end def call(env) now = Time.now status, headers, body = @app.call(env) newbody = [] body.each { |str| newbody << str } headers['X-Response-Took'] = Time.now - now [status, headers, newbody] end end class ResponseTimer class TimerProxy def initialize(body) @now = Time.now @body = body end def close @body.close if @body.respond_to?(:close) $stderr.puts({'X-Response-Took' => (Time.now - @now)}) end def each(&block) @body.each(&block) end end def initialize(app) @app = app end def call(env) status, headers, body = @app.call(env) [status, headers, TimerProxy.new(body)] end end $ time ruby foo.rb {:status=>200} {:headers=>{}} "the head tag" "the body tag" {"X-Response-Took"=>4.000268} real 0m4.044s user 0m0.029s sys 0m0.015s class ResponseTimer def initialize(app) @app = app end def call(env) status, headers, body = @app.call(env) body.extend(Module.new { now = Time.now define_method(:close) do super if defined?(super) $stderr.puts({'X-Response-Took' => (Time.now - now)}) end }) [status, headers, body] end end class EndOfLife attr_reader :callbacks def initialize(app) @app = app @callbacks = [] end def call(env) status, headers, body = @app.call(env) body.extend(Module.new { attr_accessor :eol def close super if defined?(super) eol.callbacks.each { |cb| cb.call } end }) body.eol = self [status, headers, body] end end app = FooApplication.new eol = EndOfLife.new app eol.callbacks << lambda { puts "it finished!" } rack = FakeRack.new rack.serve eol Edit: I just noticed that Rack contains a "timer" middleware similar to the one I've implemented in this blog post. You can view the broken middleware here. | |
| | | | |
www.pmatiello.me
|
|
| | | | | Dependency Injection in Ruby as inspired by Scala | |
| | | | |
gettalong.org
|
|
| | | | | Ways and strategies to keep memory usage low | |
| | | | |
www.foonathan.net
|
|
| | | When C++11 introduced move semantics, it also added two important helper functions: std::move and std::forward. They are essential when you want to manually indicate that you no longer care about an object or need to propagate the value category in generic code. As such, Ive used them countless times in the past. However, they are functions. Plain, old, standard library functions. This is problematic for multiple reasons. | ||