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

Turbo Stream与Active Job广播存在竞态条件,客户端错过更新求助

解决Turbo Stream广播早于WebSocket连接的竞态条件问题

问题场景

当前通过Turbo Stream实现WebSocket更新DOM,配置如下:

视图代码

<%= turbo_stream_from "connections_notifications" %>

控制器触发Job

PrepSidenavJob.perform_later(current_user)

Job广播逻辑

Turbo::StreamsChannel.broadcast_replace_to(
  "connections_notifications",
  target: "connections_notification",
  partial: 'product/sidenav_badge',
  locals: {count: connections_notification},
  layout: nil
)

由于Job执行速度快于客户端WebSocket连接建立,出现如下竞态顺序:

  1. 渲染初始模板
  2. 提交Job
  3. Job执行处理
  4. Job完成广播
  5. 客户端连接到/cable
  6. 客户端未收到任何更新

使用版本:Rails 7.2、@hotwired/turbo-rails 8.0.12

解决思路

1. 延迟Job执行

给Job添加延迟,预留客户端建立WebSocket连接的时间。触发Job时指定延迟时长:

PrepSidenavJob.perform_later(current_user).wait_until(2.seconds.from_now)

注意:延迟时长需根据实际环境调整,避免过长影响用户体验

2. 初始状态直接渲染

不在Job中处理初始状态的广播,而是在视图渲染时直接输出最新的connections_notification数据,后续数据变化再通过WebSocket广播:

<div id="connections_notification">
  <%= render 'product/sidenav_badge', count: current_user.connections_notification %>
</div>
<%= turbo_stream_from "connections_notifications" %>

这种方式从根源上避免初始状态的竞态问题,初始内容无需依赖Socket连接。

3. 客户端连接后主动拉取数据

监听Turbo的连接事件,在客户端成功建立WebSocket连接后,主动发起请求获取最新状态:

document.addEventListener('turbo:connect', () => {
  fetch('/api/connections_notification')
    .then(res => res.text())
    .then(html => {
      document.getElementById('connections_notification').innerHTML = html;
    });
});

需要对应新增一个API接口返回badge的HTML片段。

4. 自定义Channel主动推送初始数据

将频道改为用户专属,在客户端连接成功时,主动推送一次最新状态:

# 自定义Channel
class ConnectionsNotificationsChannel < Turbo::StreamsChannel
  def subscribed
    stream_for current_user
    # 连接成功后发送最新的badge数据
    broadcast_replace_to(
      current_user,
      target: "connections_notification",
      partial: 'product/sidenav_badge',
      locals: {count: current_user.connections_notification},
      layout: nil
    )
  end
end

视图中修改订阅代码:

<%= turbo_stream_from current_user, channel: "ConnectionsNotificationsChannel" %>

这样无论Job执行时机如何,客户端连接后都会收到最新数据,同时后续的更新也能正常广播。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 15:48:21