With puma
you can have concurrent requests. There are two concepts on how Puma can handle two incoming requests: Workers and Threads.
Puma can have multiple workers. Each worker is a process fork from puma and therefore a very heavy instance and can have multiple threads, that handle the incoming requests.
Example: A Puma server with 2 workers
and 1 thread
each can handle 2 request in parallel
. A third request has to wait until the thread of one of the workers is free.
Rails is thread-safe since version 4 (note that not all gems are thread-safe). This makes it possible to use threads in Puma to process multiple requests in a single worker. These requests are not processed in parallel, but once one thread is blocked, another can continue.
Example: A Puma server with 1 worker
and 2 threads
can handle 2 requests
. A third request has to wait until one of the two requests is finished.
Normally having multiple threads for development is fine. Puma can handle blocking threads e.g. when you place a debugger only the current request is blocked and you can still visit other sites.
In case you want to request your own application in a request itself, Puma will not allow other threads to be processed. In this case you have a deadlock until you get a request Net::Timeout
from the inner request. You can fix it by setting the number of workers >= 2.
Example for the related config/puma.rb
:
workers Integer(ENV['WEB_CONCURRENCY'] || 2)
threads_count = Integer(ENV['RAILS_MAX_THREADS'] || 5)
Note: Having multiple workers in development and tests might cause unexpected issues (database transactions and other shared states), you should not enable it just for fun. Use bundle exec puma -t 0:1 -w 1 -p 3000
to debug concurrency issues.
Settings like config.allow_concurrency = false
, config.threadsafe!
and config.middleware.delete Rack::Lock
seems not to be relevant for Rails >= 4 anymore.