Read more

Rails: Concurrent requests in development and tests

Emanuel
April 24, 2020Software engineer at makandra GmbH

With puma you can have concurrent requests. There are two concepts on how Puma can handle two incoming requests: Workers and Threads.

Workers

Illustration online protection

Rails Long Term Support

Rails LTS provides security patches for old versions of Ruby on Rails (2.3, 3.2, 4.2 and 5.2)

  • Prevents you from data breaches and liability risks
  • Upgrade at your own pace
  • Works with modern Rubies
Read more Show archive.org snapshot

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.

Threads

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.

Concurrent requests in development and tests

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.

Legacy

Settings like config.allow_concurrency = false, config.threadsafe! and config.middleware.delete Rack::Lock seems not to be relevant for Rails >= 4 anymore.

Posted by Emanuel to makandra dev (2020-04-24 17:02)