globally refactor Range handling for responses
[rainbows.git] / lib / rainbows / event_machine.rb
blobcb766694e1bc2f6c246a2c3c8a6bb519910f2960
1 # -*- encoding: binary -*-
2 require 'eventmachine'
3 EM::VERSION >= '0.12.10' or abort 'eventmachine 0.12.10 is required'
5 # Implements a basic single-threaded event model with
6 # {EventMachine}[http://rubyeventmachine.com/].  It is capable of
7 # handling thousands of simultaneous client connections, but with only
8 # a single-threaded app dispatch.  It is suited for slow clients,
9 # and can work with slow applications via asynchronous libraries such as
10 # {async_sinatra}[http://github.com/raggi/async_sinatra],
11 # {Cramp}[http://m.onkey.org/2010/1/7/introducing-cramp],
12 # and {rack-fiber_pool}[http://github.com/mperham/rack-fiber_pool].
14 # It does not require your Rack application to be thread-safe,
15 # reentrancy is only required for the DevFdResponse body
16 # generator.
18 # Compatibility: Whatever \EventMachine ~> 0.12.10 and Unicorn both
19 # support, currently Ruby 1.8/1.9.
21 # This model is compatible with users of "async.callback" in the Rack
22 # environment such as
23 # {async_sinatra}[http://github.com/raggi/async_sinatra].
25 # For a complete asynchronous framework,
26 # {Cramp}[http://m.onkey.org/2010/1/7/introducing-cramp] is fully
27 # supported when using this concurrency model.
29 # This model is fully-compatible with
30 # {rack-fiber_pool}[http://github.com/mperham/rack-fiber_pool]
31 # which allows each request to run inside its own \Fiber after
32 # all request processing is complete.
34 # Merb (and other frameworks/apps) supporting +deferred?+ execution as
35 # documented at http://brainspl.at/articles/2008/04/18/deferred-requests-with-merb-ebb-and-thin
36 # will also get the ability to conditionally defer request processing
37 # to a separate thread.
39 # This model does not implement as streaming "rack.input" which allows
40 # the Rack application to process data as it arrives.  This means
41 # "rack.input" will be fully buffered in memory or to a temporary file
42 # before the application is entered.
43 module Rainbows::EventMachine
44   autoload :ResponsePipe, 'rainbows/event_machine/response_pipe'
45   autoload :ResponseChunkPipe, 'rainbows/event_machine/response_chunk_pipe'
46   autoload :TryDefer, 'rainbows/event_machine/try_defer'
47   autoload :Client, 'rainbows/event_machine/client'
49   include Rainbows::Base
51   def init_worker_process(worker) # :nodoc:
52     Rainbows::Response.setup(Rainbows::EventMachine::Client)
53     super
54   end
56   # runs inside each forked worker, this sits around and waits
57   # for connections and doesn't die until the parent dies (or is
58   # given a INT, QUIT, or TERM signal)
59   def worker_loop(worker) # :nodoc:
60     init_worker_process(worker)
61     G.server.app.respond_to?(:deferred?) and
62       G.server.app = Rainbows::EventMachine::TryDefer[G.server.app]
64     # enable them both, should be non-fatal if not supported
65     EM.epoll
66     EM.kqueue
67     logger.info "#@use: epoll=#{EM.epoll?} kqueue=#{EM.kqueue?}"
68     client_class = Rainbows.const_get(@use).const_get(:Client)
69     max = worker_connections + LISTENERS.size
70     Rainbows::EventMachine::Server.const_set(:MAX, max)
71     Rainbows::EventMachine::Server.const_set(:CL, client_class)
72     client_class.const_set(:APP, G.server.app)
73     Rainbows::EvCore.setup
74     EM.run {
75       conns = EM.instance_variable_get(:@conns) or
76         raise RuntimeError, "EM @conns instance variable not accessible!"
77       Rainbows::EventMachine::Server.const_set(:CUR, conns)
78       EM.add_periodic_timer(1) do
79         unless G.tick
80           conns.each_value { |c| client_class === c and c.quit }
81           EM.stop if conns.empty? && EM.reactor_running?
82         end
83       end
84       LISTENERS.map! do |s|
85         EM.watch(s, Rainbows::EventMachine::Server) do |c|
86           c.notify_readable = true
87         end
88       end
89     }
90   end
91 end
92 # :enddoc:
93 require 'rainbows/event_machine/server'