Module: LongBody::HijackHandler
Overview
The problem with fast each() bodies is that the Ruby process will enter a busy wait if the write socket for the webserver is saturated.
We can bypass that by releasing the CPU using a select(), but for that we have to use “rack.hijack” in combination with a nonblocking write.
For more on this: apidock.com/ruby/IO/write_nonblock old.blog.phusion.nl/2013/01/23/the-new-rack-socket-hijacking-api/
Constant Summary collapse
- HIJACK_HEADER =
'rack.hijack'.freeze
Instance Method Summary collapse
Instance Method Details
#create_socket_writer_lambda_with_body(rack_response_body) ⇒ Object
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/long_body/hijack_handler.rb', line 20 def create_socket_writer_lambda_with_body(rack_response_body) lambda do |socket| begin rack_response_body.each do | chunk | begin num_bytes_written = socket.write_nonblock(chunk) # If we could write only partially, make sure we do a retry on the next # iteration with the remaining part if num_bytes_written < chunk.bytesize chunk = chunk[num_bytes_written..-1] raise Errno::EINTR end rescue IO::WaitWritable, Errno::EINTR # The output socket is saturated. # If we are running within a threaded server, # let another thread preempt here. We are waiting for IO # and some other thread might have things to do here. IO.select(nil, [socket]) # ...then wait on the socket to be writable again retry # and off we go... rescue Errno::EPIPE, Errno::EPROTOTYPE # Happens when the client aborts the connection return end end ensure rack_response_body.close if rack_response_body.respond_to?(:close) socket.close if socket.respond_to?(:closed?) && socket.respond_to?(:close) && !socket.closed? end end end |
#perform(env, s, h, b) ⇒ Object
14 15 16 17 18 |
# File 'lib/long_body/hijack_handler.rb', line 14 def perform(env, s, h, b) # Replace the output with our socket moderating technology 2.0 h[HIJACK_HEADER] = create_socket_writer_lambda_with_body(b) [s, h, []] # Recommended response body for partial hijack is an empty Array end |