如何找出谁连接到 ActionCable?

Posted

技术标签:

【中文标题】如何找出谁连接到 ActionCable?【英文标题】:How do I find out who is connected to ActionCable? 【发布时间】:2016-07-06 12:22:52 【问题描述】:

我见过ActionCable.server.open_connections_statisticsActionCable.server.connections.lengthActionCable.server.connections.map(&:statistics)ActionCable.server.connections.select(&:beat).count 等,但这只是“每个进程”(服务器、控制台、服务器工作者等)。我如何找出目前订阅 ActionCable 的每个人?这应该在每个环境(开发、登台、生产)中的任何 Rails 进程上返回相同的值。例如,在开发控制台中,您还可以看到开发服务器上的连接,因为理论上它们使用相同的订阅适配器(redis、async、postgres)。

Rails 5.0.0.beta3、Ruby 2.3.0

相关ActionCable - how to display number of connected users?

【问题讨论】:

【参考方案1】:

如果使用redis,您可以看到所有的 pubsub 频道。

[2] pry(main)> Redis.new.pubsub("channels", "action_cable/*")
[
    [0] "action_cable/Z2lkOi8vbWFvY290LXByb2plL3QvUmVzcG9uXGVyLzEx",
    [1] "action_cable/Z2lkOi8vbWFvY290LXByb2plL3QvUmVzcG9uXGVyLzI"
]

这将显示所有 Puma 工作人员的所有 websocket 连接。如果您有多个服务器,它可能也会在此处显示这些服务器。

【讨论】:

有没有办法区分它们,比如按房间或其他? @LoaiGhoraba 我在下面看不到答案。你在其他地方有答案吗? 您知道:您可以对字符串进行 decode64(当然是在斜线之后)并得到如下内容:gid://myproject/User/250581 这个字符串取决于您使用的 identify_by 我猜。跨度> Redis.new(url: 'redis://:auth_code@ip:port/db_number').pubsub('channels', 'action_cable/*').map |c| Base64.decode64(c.split('/').last) 使用ActionCable.server.pubsub.send(:redis_connection)获取ActionCable的Redis连接(而不是自己创建),使用ActionCable.server.pubsub.send(:channel_with_prefix, "action_cable/*")获取正确的通道名称【参考方案2】:

更具体的ActionCable(和 Redis)...

假设这个频道:

class RoomChannel < ApplicationCable::Channel
end

从 ActionCable 获取 Redis 适配器,而不是自己创建 (否则您需要提供来自 config/cable.yml 的 URL):

pubsub = ActionCable.server.pubsub

获取频道名称,包括您可能指定的频道前缀 在config/cable.yml:

channel_with_prefix = pubsub.send(:channel_with_prefix, RoomChannel.channel_name)

RoomChannel获取所有连接的频道:

# pubsub.send(:redis_connection) actually returns the Redis instance ActionCable uses
channels = pubsub.send(:redis_connection).
  pubsub('channels', "#channel_with_prefix:*")

解码订阅名称:

subscriptions = channels.map do |channel|
   Base64.decode64(channel.match(/^#Regexp.escape(channel_with_prefix):(.*)$/)[1])
end

如果您订阅了ActiveRecord 对象,假设为Room(使用stream_for), 您可以提取 ID:

# the GID URI looks like that: gid://<app-name>/<ActiveRecordName>/<id>
gid_uri_pattern = /^gid:\/\/.*\/#Regexp.escape(Room.name)\/(\d+)$/
chat_ids = subscriptions.map do |subscription|
  subscription.match(gid_uri_pattern)
  # compacting because 'subscriptions' include all subscriptions made from RoomChannel,
  # not just subscriptions to Room records
end.compact.map  |match| match[1] 

【讨论】:

NoMethodError(#<:subscriptionadapter::async:0x00007f2b20a45d88> 的未定义方法 `channel_with_prefix') @FavouriteOnwuemene 你在使用 Redis 吗?我写这个答案是专门为 Redis 写的。我可以看到这个方法在 Rails 5.2.3 (github.com/rails/rails/blob/v5.2.3/actioncable/lib/action_cable/…) 中仍然存在,但是 ChannelPrefix 包含在 redis.rb 中而不是 async.rb 或 postgresql.rb 中。

以上是关于如何找出谁连接到 ActionCable?的主要内容,如果未能解决你的问题,请参考以下文章

无法连接到 Elastic Beanstalk 上的 ActionCable

ActionCable 不再在生产环境中工作

ActionCable - 如何显示连接用户的数量?

如何在 minitest 中模拟和验证 ActionCable 传输?

如何使用 RSpec 测试 ActionCable 频道?

如何使用 ActionCable 作为 API