Raise ActiveRecord connection pool size versus extend checkout_timeout to mitigate intermittent thread wait spikes under concurrent load
0 reputation · 28 Mar 2024, 19:11 UTC
0 reputation · 28 Mar 2024, 19:11 UTC
Goal: Determine whether intermittent ActiveRecord connection pool exhaustion in a Rails application should be addressed by increasing the per-process connection pool size or by extending the checkout_timeout threshold, given that thread concurrency and database connection limits interact non-linearly across processes.
Constraints and uncertainty: Pool size is per process; total database connections equal pool size multiplied by the number of running processes (e.g., Puma workers, Sidekiq workers), which can silently exceed PostgreSQL's max_connections. checkout_timeout only controls wait duration before raising ConnectionTimeoutError and does not free held connections. Rails version defaults and thread consumers (especially with async_query_executor in Rails 7.1+) affect which threads hold connections. Metrics such as pool busy/waiting counts and database activity views often cannot distinguish between capacity shortage and connection-holding leaks or long-running transactions.
32275 reputation · 29 Mar 2024, 02:26 UTC
To mitigate intermittent thread wait spikes, increase the connection pool size if your concurrent thread count exceeds available connections. Do not extend the checkout_timeout as a primary fix; doing so merely defers the ConnectionTimeoutError and increases request latency without increasing the application's capacity to handle concurrent database work.
The two settings address entirely different failure modes:
(pool_size * number_of_processes).max_connections (e.g., in PostgreSQL via SHOW max_connections;). Ensure the total is lower than the database limit to avoid "too many clients" errors.database.yml: Increase the pool value to match or slightly exceed the maximum number of threads configured for your web server (Puma) or background processor (Sidekiq).ActiveRecord::ConnectionTimeoutError and check that database connection counts remain stable under load.This recommendation assumes the exhaustion is caused by high concurrency. If the pool is exhausted despite a high pool size, you may have a connection leak (e.g., manual connection.checkout calls without a corresponding checkin) or long-running transactions that hold connections idle. In Rails 7.1+, the introduction of async query execution can alter connection checkout patterns, potentially increasing the frequency of pool requests.
To refine this recommendation: What is the current ratio of your Puma/Sidekiq thread count to your ActiveRecord pool size? If the pool size is already equal to or greater than the thread count, the issue is likely connection leakage or slow queries rather than a capacity shortage.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.