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

如何在ActionCable中获取全部活跃连接?实现聊天在线检测与通知

解决方案

1. 维护用户-频道订阅映射(生产环境推荐)

ActionCable.server.connections在多进程/多服务器部署下完全不可靠,每个进程仅维护自身的连接池,无法跨进程共享状态。正确思路是主动记录用户的订阅行为:

  • 在频道类中记录订阅状态
    重写聊天频道的subscribed和unsubscribed方法,用Redis(或其他共享存储)存储用户与频道的关联:

    class ChatChannel < ApplicationCable::Channel
      def subscribed
        room_id = params[:room_id]
        # 用Redis集合存储用户订阅的频道
        Redis.current.sadd("user:#{current_user.id}:subscribed_rooms", room_id)
        stream_from "chat_#{room_id}"
      end
    
      def unsubscribed
        room_id = params[:room_id]
        Redis.current.srem("user:#{current_user.id}:subscribed_rooms", room_id)
      end
    end
    
  • 判断用户是否在目标频道
    发送消息时直接查询Redis,验证接收方的订阅状态:

    def send_message
      recipient_id = params[:recipient_id]
      # 双人聊天房间ID建议用用户ID有序组合,避免重复
      room_id = [current_user.id, recipient_id].sort.join('_')
      
      is_subscribed = Redis.current.sismember("user:#{recipient_id}:subscribed_rooms", room_id)
      unless is_subscribed
        # 执行通知逻辑,如推送、存储待读消息
        Notification.create(user_id: recipient_id, content: params[:content], room_id: room_id)
      end
    
      ActionCable.server.broadcast("chat_#{room_id}", message: params[:content])
    end
    

2. 单进程环境下的连接过滤方案

如果仅单进程部署,可以通过current_user过滤连接,替代直接遍历所有连接:

# 筛选目标用户的所有活跃连接
user_connections = ActionCable.server.connections.select do |conn|
  conn.current_user&.id == recipient_id
end

# 检查是否有连接订阅了目标频道
is_in_channel = user_connections.any? do |conn|
  conn.subscriptions.any? { |sub| sub.channel == ChatChannel && sub.params[:room_id] == room_id }
end

注意:该方案仅适用于开发或单进程部署,生产多进程/多服务器场景完全失效。

3. 确保连接与用户的正确绑定

在ApplicationCable::Connection中正确设置用户标识,保证连接与用户的关联准确:

class ApplicationCable::Connection < ActionCable::Connection::Base
  identified_by :current_user

  def connect
    self.current_user = find_verified_user
  end

  private
  def find_verified_user
    # 根据你的认证逻辑获取用户,比如通过session或token
    current_user = User.find_by(id: cookies.signed[:user_id])
    current_user ? current_user : reject_unauthorized_connection
  end
end

核心注意点

  • 永远不要依赖ActionCable.server.connections做跨进程状态查询,仅单进程场景可用。
  • 生产环境必须用共享存储(Redis最优)维护订阅状态,保证多部署环境下的一致性。
  • 双人聊天房间ID建议用用户ID有序组合,避免同一对用户出现两个不同的房间标识。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 17:02:24