You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.01 01:22:33