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

Kamal部署Sinatra应用遭遇Grover::JavaScript::TimeoutError求助

解决Sinatra+Grover调用自身路由超时的问题

你的问题核心是Sinatra默认使用的WEBrick服务器是单线程单进程模式,同一时间只能处理一个请求。当/pdf3的请求触发Grover去请求自身的/up路由时,主进程正被/pdf3占用,无法响应这个内部请求,导致Chrome等待超时,最终抛出Grover::JavaScript::TimeoutError。

下面是具体的解决办法:

方案1:替换为多线程/多进程服务器(最直接有效)

Sinatra默认的WEBrick不适合生产环境并发场景,换成Puma服务器,它支持多线程+多进程,能同时处理多个请求。

操作步骤:

  1. 在Gemfile中添加Puma依赖:
gem 'puma'
  1. 执行bundle install更新依赖包。
  2. 修改Dockerfile的启动命令,用Puma替代默认的rackup:
CMD ["bundle", "exec", "puma", "--bind", "0.0.0.0:4567", "--threads", "2:16", "--workers", "2"]

说明:--threads 2:16表示每个进程的线程数范围为2-16,--workers 2表示启动2个工作进程,可根据服务器CPU核心数调整(比如4核CPU可设为4个workers)。

  1. 修正Kamal的健康检查配置,匹配实际的路由和端口:
healthcheck:
  path: /up
  port: 4567

方案2:直接渲染内容,避免内部请求(更高效)

如果/up路由仅返回简单文本,没必要通过Grover发起HTTP请求,直接把内容传给Grover,跳过请求环节,既避免死锁又提升性能。

修改/pdf3路由代码:

get '/pdf3' do
  # 直接传入HTML内容,无需请求外部URL
  grover = Grover.new("<html><body>UP</body></html>", base_url: "https://myserver.com")
  content_type 'application/pdf'
  attachment 'output.pdf'
  grover.to_pdf
end

说明:base_url用于处理内容中的相对资源路径,若内容无相对路径可省略。

方案3:调整Nginx和Kamal代理配置(辅助优化)

  1. 移除Nginx的limit_rate 50k限制,该限速会拖慢内部请求,加剧超时风险,同时补充必要的代理头:
server {
    server_name myserver.com;
    access_log off;

    location / {
        proxy_pass http://127.0.0.1:8081;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
  1. 确认Kamal的Traefik配置中,端口转发规则匹配应用实际端口(你的应用容器端口为4567,Traefik转发到8081的配置是正确的)。

验证方法

部署修改后的代码后,访问/pdf3测试是否正常生成PDF。可通过curl -v https://myserver.com/pdf3查看请求过程,或查看应用日志确认并发请求是否被正常处理。

内容的提问来源于stack exchange,提问作者map7

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 14:32:10