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

Rails ActionCable频道异常重复订阅/退订问题排查

问题

我正在开发展示特定页面(名为'matter')当前在线用户的功能:

在show.html.erb中使用的代码:

<%= turbo_stream_from("matter_online_assessors", channel: MatterOnlineAssessorsChannel, data: { matter_id: @matter.id }) %>

对应的MatterOnlineAssessorsChannel代码如下:

class MatterOnlineAssessorsChannel < Turbo::StreamsChannel
  before_subscribe :set_matter
  before_unsubscribe :set_matter

  def subscribed
    super
    return unless current_user
    @matter.online_assessors << current_user.id 

    Turbo::StreamsChannel.broadcast_append_to(
      verified_stream_name_from_params,
      target: 'matter_online_assessors',
      partial: 'assessors/matters/online_assessor',
      locals: { assessor: current_user }
    )
  end

  def unsubscribed
    return unless current_user
    @matter.online_assessors.remove(current_user.id) # redis list

    Turbo::StreamsChannel.broadcast_remove_to(
      verified_stream_name_from_params,
      target: ActionView::RecordIdentifier.dom_id(current_user)
    )
  end

  private
    def set_matter
      @matter = Matter.find(params[:matter_id])
    end
end

现象:首次进入show页面仅触发1次订阅事件,正常;离开页面触发退订后再次访问,会出现订阅→退订→订阅的异常重复事件,请问可能的原因是什么?


可能的原因分析

  • Turbo Drive页面持久化导致重复订阅:Turbo Drive会缓存页面状态,用户返回页面时可能重新执行turbo_stream_from的订阅逻辑,而之前的WebSocket连接未完全断开,旧连接触发退订、新连接触发订阅,形成异常事件序列。
  • WebSocket连接销毁延迟:离开页面时WebSocket连接的销毁存在延迟,若用户快速再次进入页面,旧连接的退订事件才触发,同时新订阅已建立,从而出现订阅→退订→订阅的重复流程。
  • DOM元素未被正确替换:Turbo导航后,页面中turbo_stream_from相关DOM元素未被完全替换,导致多个订阅实例共存,每次进入页面新增一个订阅,旧订阅在离开时才触发退订。
  • Turbo导航事件顺序问题:Turbo页面导航时的事件触发顺序可能导致退订操作延迟,用户快速返回页面时,前一次的退订操作才完成,新的订阅已发起,进而出现重复事件。
  • 连接标识冲突:如果turbo_stream_from生成的流名称或客户端标识存在重复,可能导致服务器端对连接的订阅/退订状态判断出错,触发额外的事件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 11:17:22