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

Puma服务器缓冲响应,SSE无法按间隔实时输出问题求助

解决Rails 7.0.4 ActionController::Live SSE 响应缓冲问题

核心问题分析

你的问题根源在于Puma默认会缓冲响应内容,直到流关闭才一次性发送,即便设置了flush_headers: true,如果没有手动触发流刷新,依然无法实时推送内容。另外,Rails的部分默认中间件、curl自身的缓冲也可能干扰实时输出。

解决方案步骤

1. 修正控制器代码,手动刷新流

确保每次写入后调用response.stream.flush,同时配置正确的SSE响应头,处理客户端断开异常:

class StreamsController < ApplicationController
  include ActionController::Live

  def stream
    # 配置SSE必需的响应头
    response.headers['Content-Type'] = 'text/event-stream'
    response.headers['Cache-Control'] = 'no-cache'
    response.headers['Connection'] = 'keep-alive'
    response.headers['X-Accel-Buffering'] = 'no' # 禁用反向代理/中间件缓冲

    5.times do |i|
      response.stream.write "data: hello world #{i+1}\n\n"
      response.stream.flush # 关键:手动触发内容推送
      sleep 1
    end
  rescue IOError
    # 捕获客户端中途断开连接的异常,避免服务器报错
  ensure
    response.stream.close
  end
end

2. 调整Puma配置,确保实时推送

在config/puma.rb中,除了flush_headers: true,还需添加连接超时配置,避免连接被提前回收:

workers ENV.fetch("WEB_CONCURRENCY") { 2 }
threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
threads threads_count, threads_count

on_worker_boot do
  ActiveRecord::Base.establish_connection if defined?(ActiveRecord)
end

# 绑定端口时配置实时推送参数
server_opts = {
  flush_headers: true,
  persistent_timeout: 20 # 保持长连接的超时时间
}

bind "tcp://0.0.0.0:#{ENV.fetch("PORT") { 3000 }}", server_opts

3. 禁用curl自身缓冲

使用curl测试时,添加-N参数禁用curl的输出缓冲,确保实时看到推送内容:

curl -N http://localhost:3000/stream

4. 排除中间件干扰

如果上述步骤仍无效,可在控制器中跳过可能导致缓冲的默认中间件:

skip_after_action :set_cache_control_headers # 避免缓存头覆盖自定义配置
skip_before_action :verify_authenticity_token # 开发环境临时跳过,生产环境按需配置

原理说明

  • response.stream.flush会强制将缓冲区内容发送给客户端,而不是等待流关闭。
  • X-Accel-Buffering: no会通知所有中间层(包括Rails内部中间件、反向代理)禁止缓冲响应内容。
  • Puma的flush_headers: true确保响应头立即发送,而persistent_timeout维持长连接,保证SSE流不被提前断开。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 13:45:32