Rails 7应用使用Turbo Streams广播运行后出现挂起无响应问题
解决Rails 7 Turbo Streams广播导致页面停滞无响应的问题
问题描述
Rails 7应用启用Turbo Streams广播功能后,运行一段时间会出现页面加载停滞、无响应的情况。应用日志显示WebSocket连接成功升级、Turbo::StreamsChannel开始从assign_employees_7进行流传输后,服务器不再接收新请求;本地运行应用一段时间后也会出现该问题,且服务器性能无异常。
相关代码如下:
控制器代码
Turbo::StreamsChannel.broadcast_update_to("assign_employees_#{company.id}", target: "assign_employees_#{company.id}", partial: 'activities/assign_employees', locals: { activities: activities, calendars: company.calendars, shifts: shifts, company: company, group_id: session[:group_id] })
视图代码
<%= turbo_stream_from "assign_employees_#{current_company.id}" %> <%= render 'assign_employees', activities: @activities, calendar: @calendars, shifts: @shifts, company: current_company, group_id: session[:group_id] %>
解决方案
排查WebSocket连接泄漏
页面刷新或用户离开时,Turbo理论上会自动断开WebSocket连接,但前端异常(如页面未正常卸载)可能导致连接堆积,耗尽服务器连接数。- 前端添加连接清理逻辑:
window.addEventListener('beforeunload', () => { if (Turbo.session?.streamSource) { Turbo.disconnectStreamSource(Turbo.session.streamSource); } }); - 在Rails控制台执行
ActionCable.server.connections.size,查看连接数是否持续增长,确认是否存在泄漏。
- 前端添加连接清理逻辑:
异步处理广播渲染
广播时同步渲染partial若包含大量数据或复杂逻辑,会阻塞请求线程,导致服务器无法处理新请求。用ActiveJob封装广播操作:class BroadcastAssignEmployeesJob < ApplicationJob queue_as :default def perform(company, activities, shifts, group_id) # 预加载关联数据,避免N+1查询 company = company.includes(:calendars) Turbo::StreamsChannel.broadcast_update_to( "assign_employees_#{company.id}", target: "assign_employees_#{company.id}", partial: 'activities/assign_employees', locals: { activities: activities, calendars: company.calendars, shifts: shifts, company: company, group_id: group_id } ) end end控制器中替换为异步调用:
BroadcastAssignEmployeesJob.perform_later(company, activities, shifts, session[:group_id])验证频道订阅合理性
确认assign_employees_#{company.id}频道是否被不必要用户订阅,导致广播负载过高。修改Turbo::StreamsChannel添加订阅日志:class Turbo::StreamsChannel < ActionCable::Channel::Base def subscribed stream_from params[:stream] Rails.logger.info "User #{current_user&.id} subscribed to stream: #{params[:stream]}" end end检查日志是否存在异常订阅情况,比如非目标公司用户订阅了频道。
优化服务器配置
若使用Puma,调整config/puma.rb的线程和进程配置,避免连接耗尽:max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } threads min_threads_count, max_threads_count workers ENV.fetch("WEB_CONCURRENCY") { 2 }确保
config/cable.yml中生产环境使用redis适配器(本地开发可用async),避免连接泄漏。排查前端Turbo异常
打开浏览器开发者工具Console面板,检查是否存在JavaScript错误:- 确认
target: "assign_employees_#{company.id}"对应的DOM元素始终存在,避免因元素缺失导致Turbo流处理失败阻塞后续操作; - 检查是否有其他前端脚本干扰Turbo的正常运行。
- 确认
内容的提问来源于stack exchange,提问作者cccvandermeer
相关产品推荐
相关产品推荐

