Method: Puma::Server#reactor_wakeup

Defined in:
lib/puma/server.rb

#reactor_wakeup(client) ⇒ Object

This method is called from the Reactor thread when a queued Client receives data, times out, or when the Reactor is shutting down.

While the code lives in the Server, the logic is executed on the reactor thread, independently from the server.

It is responsible for ensuring that a request has been completely received before it starts to be processed by the ThreadPool. This may be known as read buffering. If read buffering is not done, and no other read buffering is performed (such as by an application server such as nginx) then the application would be subject to a slow client attack.

For a graphical representation of how the request buffer works see [architecture.md](github.com/puma/puma/blob/master/docs/architecture.md#connection-pipeline).

The method checks to see if it has the full header and body with the ‘Puma::Client#try_to_finish` method. If the full request has been sent, then the request is passed to the ThreadPool (`@thread_pool << client`) so that a “worker thread” can pick up the request and begin to execute application logic. The Client is then removed from the reactor (return `true`).

If a client object times out, a 408 response is written, its connection is closed, and the object is removed from the reactor (return ‘true`).

If the Reactor is shutting down, all Clients are either timed out or passed to the ThreadPool, depending on their current state (#can_close?).

Otherwise, if the full request is not ready then the client will remain in the reactor (return ‘false`). When the client sends more data to the socket the `Puma::Client` object will wake up and again be checked to see if it’s ready to be passed to the thread pool.



319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
# File 'lib/puma/server.rb', line 319

def reactor_wakeup(client)
  shutdown = !@queue_requests
  if client.try_to_finish || (shutdown && !client.can_close?)
    @thread_pool << client
  elsif shutdown || client.timeout == 0
    client.timeout!
  else
    client.set_timeout(@first_data_timeout)
    false
  end
rescue StandardError => e
  client_error(e, client)
  close_client_safely(client)
  true
end