Ruby中调用HTTP API的代码导致进程挂起的原因排查
你的Rails进程挂起原因及解决方案
嘿,我来帮你拆解下这个问题——你遇到的进程挂起和JSON.parse与HTTP.get写在同一行、或者多次调用完全没关系,核心原因是单线程Rails服务器的死锁问题!
为什么会挂起?
默认情况下,Rails使用的是WEBrick这类单线程服务器(如果你没特意切换到Puma等多线程/多进程服务器的话)。当你的控制器动作发起HTTP.get('http://localhost:3000/...')请求时,这个请求是发给当前正在运行的Rails服务器的。但此时服务器正忙着处理你当前的页面请求,根本腾不出手来处理这个新的API请求,于是两个请求互相等待,形成了死锁,进程自然就卡住不动了,只能用kill -9强制终止。
解决办法
根据你的需求,有几个可行的方案:
1. 切换到多线程/多进程服务器
最直接的方式是换成Puma(现在Rails默认的服务器),并配置多线程或多进程,让服务器可以同时处理多个请求:
- 启动服务器时指定工作进程数:
rails s -w 2 - 或者在
config/puma.rb里配置更详细的参数:workers 2 threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } threads threads_count, threads_count
这样当控制器发起API请求时,另一个线程/进程可以处理这个请求,不会造成死锁。
2. 直接调用业务逻辑,跳过HTTP请求
如果这个API是你自己的Rails应用提供的,完全没必要绕HTTP这一圈——直接调用对应的模型或服务层代码就行。比如你的API返回的是商品数据,那控制器里可以直接写:
@products = Product.all # 或者你API里的具体业务逻辑,比如过滤、分页等
这种方式不仅避免了死锁,还比HTTP请求高效得多。
3. 把API服务单独部署到另一个端口
如果你必须通过HTTP调用,那可以把API服务启动在另一个端口,比如:
rails s -p 3001
然后控制器里的请求地址改成:
parsed_response = JSON.parse(HTTP.get('http://localhost:3001/api/v2/storefront/products'))
这样两个服务互不干扰,就不会出现阻塞问题了。
内容的提问来源于stack exchange,提问作者jbk
相关产品推荐
相关产品推荐

