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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 16:42:46