Puma
Table of Contents
:ID: 4ED73BAB-481F-4CFA-9449-EA46446C07DF
# Puma Concurrency and Load Balancing
See also https://github.com/puma/puma/blob/master/docs/architecture.md
graph TD
A[Client Connections] --> B[Socket Accept Queue]
B --> C[Shared Listening Socket]
C --> D1[Worker 1]
C --> D2[Worker 2]
C --> D3[Worker 3]
D1 --> E1[Thread Pool 1]
D2 --> E2[Thread Pool 2]
D3 --> E3[Thread Pool 3]
subgraph Operating System
B
C
end
subgraph Puma
D1
D2
D3
E1
E2
E3
end
# Concurrency Model
- Threads: Each Puma worker has a thread pool to handle multiple requests concurrently.
- Configured via:
threads min_threads, max_threads
- Configured via:
- Workers: Separate processes forked from the master process.
- Configured via:
workers count - Each worker has its own thread pool.
- Configured via:
# Load Balancing and Socket Accept Queue
- The master process creates a shared listening socket.
- All workers inherit this socket and compete to accept connections.
- The OS manages a socket accept queue for incoming TCP connections.
- When a connection is ready, the OS “wakes” one of the sleeping workers to handle it.
# Sleep and Wake Behavior
- When a worker thread is ready to accept a request, it blocks (sleeps) until a connection is available.
- The OS “wakes” up one thread or process to handle the connection.
# Low level error handler
See also https://github.com/puma/puma/blob/master/README.md#error-handling
In config/puma.rb
lowlevel_error_handler do |e, env, status| # Do stuff like report the error to your favorite error tracking service # the `env` object could have useful data to include in the reporting: # env['REQUEST_URI'] # env['PATH_INFO'] # env['REQUEST_METHOD'] # env['REMOTE_ADDR'] [500, {}, ["An error has occurred. Try again."]] end
# Test it
Maybe try to send a malformed HTTP request using nc or openssl (if running
on 443) but probably the easiest way is to inject some middleware in config.ru
that just raises an error:
class LowleveErrorTest def initialize(app) @app = app end def call(env) raise "Simulated crash before app" end end use LowlevelErrorTest run Rails.application Rails.application.load_server