Rails 5 Puma开发服务器同时接收多请求时挂起问题求助
我之前在开发Rails 5项目时也碰到过一模一样的情况——前端同时发五六个POST请求,Puma服务器直接僵死,连Ctrl+C都杀不掉,只能手动找端口进程干掉,而且完全没错误日志,排查起来特别头疼。结合当时踩过的坑,给你几个针对性的解决方案:
1. 先调整Puma的开发环境并发配置
默认情况下,Puma在开发环境是单线程运行的,处理多个并发请求时会排队,一旦某个请求卡住,整个服务器就僵住了。你可以在config/puma/development.rb(如果没有就新建一个)里修改配置:
# config/puma/development.rb # 设置线程数,开发环境5-10足够 threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } threads threads_count, threads_count port ENV.fetch("PORT") { 3000 } environment ENV.fetch("RAILS_ENV") { "development" } # 开发环境开1个进程就行,多线程就能处理并发 workers ENV.fetch("WEB_CONCURRENCY") { 1 } # 预加载应用,加上worker启动时重建数据库连接,避免连接池混乱 preload_app! on_worker_boot do ActiveRecord::Base.establish_connection if defined?(ActiveRecord) end
改完后重启服务器,多线程配置能让Puma同时处理多个请求,不会因为单个请求阻塞就全挂了。
2. 匹配数据库连接池大小
数据库连接池的默认大小可能和你的Puma线程数不匹配,导致请求拿不到数据库连接而挂起。打开config/database.yml,在development节点里调整pool大小:
development: adapter: postgresql # 或者你用的其他数据库 database: your_app_development pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 10 } %> # 至少等于Puma线程数 # 其他配置...
确保连接池大小≥Puma的线程数,这样每个线程都能拿到数据库连接,不会卡在等待连接的环节。
3. 排查请求里的阻塞代码
如果上面两步没用,大概率是某个请求里有同步阻塞的操作——比如调用外部API没设超时、执行长时间的计算、或者死循环。举个例子:
# 控制器里的坏例子:同步调用慢API,没超时设置 def create @data = Net::HTTP.get(URI('https://slow-third-party-api.com/data')) # 后续操作... end
这种情况一旦第三方API响应慢,整个线程就卡住了。改成带超时的调用:
require 'timeout' def create begin Timeout.timeout(5) do # 5秒超时 @data = Net::HTTP.get(URI('https://slow-third-party-api.com/data')) end rescue Timeout::Error render json: { error: "请求超时" }, status: 500 return end # 后续操作... end
或者用HTTParty、Faraday这类支持超时配置的HTTP库,避免单个请求拖垮整个服务器。
4. 临时关闭开发环境的自动重载
Rails开发环境的代码自动重载(比如Spring或者内置的reloader)有时候会和并发请求冲突,导致服务器僵死。你可以临时关闭试试:
# 启动服务器时禁用Spring DISABLE_SPRING=1 rails s
或者在config/environments/development.rb里关闭自动重载:
config.cache_classes = true # 临时测试用,关闭后修改代码需要重启服务器
如果关闭后问题消失,那就是自动重载机制的锅,可以考虑升级Spring版本,或者在开发环境用puma-dev替代默认的服务器启动方式。
5. 用Puma调试模式看状态
启动服务器时加上--debug参数,能看到Puma的线程处理日志,方便排查哪个请求卡住了:
rails s --debug
这样你能看到每个请求的线程状态,找到阻塞的根源。
内容的提问来源于stack exchange,提问作者dcporter7

