【问题标题】:How do I find out who is connected to ActionCable?如何找出谁连接到 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?

【问题讨论】:

    标签: ruby publish-subscribe subscriptions ruby-on-rails-5 actioncable


    【解决方案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 中。
    猜你喜欢
    • 2019-10-23
    • 2019-04-11
    • 1970-01-01
    • 1970-01-01
    • 2016-11-09
    • 2016-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多