无法使用 graphql-ruby 订阅进行简单广播

Posted

技术标签:

【中文标题】无法使用 graphql-ruby 订阅进行简单广播【英文标题】:Can't get a simple broadcast with graphql-ruby subscriptions working 【发布时间】:2021-01-19 15:39:36 【问题描述】:

我有一个准系统设置,用于通过 Action Cable 使用 graphql-ruby 进行更新广播。

客户端在订阅时收到初始有效负载。 客户端没有收到任何更新并且订阅类型的update 方法没有被调用。后端没有错误。触发调用似乎被默默地忽略了。这就是我要解决的问题/正确理解它应该如何工作。

我正在查看的文档:

https://graphql-ruby.org/subscriptions/subscription_classes.html https://graphql-ruby.org/subscriptions/triggers

订阅类型:

module Types
  class SubscriptionType < Types::BaseObject
    field :server_info, subscription: Subscriptions::ServerInfoSubscription, null: false
  end
end
module Subscriptions
  class ServerInfoSubscription < Subscriptions::BaseSubscription
    field :date_time, GraphQL::Types::ISO8601DateTime, null: false

    def subscribe
       date_time: DateTime.now 
    end

    def update
      puts 'UPDATE CALLED' # Nope, it's not being called
      super
    end
  end
end

我尝试触发更新的方式:

MySchema.subscriptions.trigger(:server_info, ,  date_time: DateTime.now )

架构定义为:

class MySchema < GraphQL::Schema
  use GraphQL::Execution::Interpreter
  use GraphQL::Subscriptions::ActionCableSubscriptions

  subscription(Types::SubscriptionType)
end

我在config/cable.yml中使用redis适配器开发环境:

development:
  adapter: redis
  url: <%= ENV.fetch("REDIS_URL")  "redis://localhost:6379/1"  %>
  channel_prefix: test-app_development

我错过了什么?有任何故障排除提示吗?

更新:

一些诊断:

初始(和成功)订阅调用的 Rails 日志:

GraphqlChannel#execute("query"=>"subscription ServerInfoSubscription \n  serverInfo \n    dateTime\n    __typename\n  \n\n", "variables"=>, "operationName"=>"ServerInfoSubscription")
GraphqlChannel transmitting "data"=>"serverInfo"=>"dateTime"=>"2020-10-08T10:47:08-04:00", "__typename"=>"ServerInfoSubscriptionPayload"
GraphqlChannel is streaming from graphql-subscription:9087735b-9b99-4d66-8b77-ff3622c8efe7
GraphqlChannel is streaming from graphql-event::dateTime:
Started POST "/graphql" for 192.168.64.210 at 2020-10-08 10:47:08 -0400

检查活动的 Redis PubSub 频道:

$ redis-cli -h 192.168.64.210 -p 6379 pubsub channels
1) "test-app_development:graphql-subscription:9087735b-9b99-4d66-8b77-ff3622c8efe7"
2) "test-app_development:graphql-event::dateTime:"
3) "_action_cable_internal"

在 Rails 控制台中运行触发器调用的结果:

irb(main):001:0> MySchema.subscriptions.trigger(:server_info, ,  date_time: DateTime.now )
[ActionCable] Broadcasting to graphql-event::serverInfo:: "\"date_time\":\"2020-10-08T10:54:18-04:00\",\"__sym_keys__\":[\"date_time\"]"

显而易见的是,Redis PubSub 频道称为“graphql-event::dateTime:”,而触发器调用通过不存在的“graphql-event::serverInfo:”频道进行广播。我不明白为什么实际的 Redis 通道被称为“graphql-event::dateTime”,而订阅查询位于***“ServerInfo”类型。

【问题讨论】:

如果您实际上已成功订阅查询,我希望redis-cli 会向您显示类似test-app_development:graphql-subscription:UUID:serverInfo 的内容。我认为您可能需要在 SubscriptionType 类中添加 extend GraphQL::Subscriptions::SubscriptionRoot @Unixmonkey 我在基本订阅类中有它。但是 graphql-ruby 正在记录一个警告,说它不再需要包含在内。所以我删除了它。那不是问题。 【参考方案1】:

我终于让它工作了,但无法确定为什么它不起作用:

MySchema.subscriptions.trigger(:server_info, ,  date_time: DateTime.now )

请注意,我一直在传递一个空哈希 () 作为第二个参数。

我让它工作的方式是在我的查询中添加一个argument 并使用匹配的参数(匹配到原始订阅查询)。像这样的:

module Subscriptions
  class EventReceivedSubscription < Subscriptions::BaseSubscription
    argument :event_name, String, required: true

    field :event_name, String, null: false
    field :payload, String, null: true
  end
end
MySchema.subscriptions.trigger(
  :event_received,
   event_name: 'greeting' ,
   payload: 'Hello' 
)

我现在可以看到的 Redis 频道是:

$ redis-cli -h 192.168.64.210 -p 6379 pubsub channels
1) "test-app_development:graphql-event::eventReceived:eventName:greeting"

【讨论】:

【参考方案2】:

这是因为您尝试覆盖的方法需要参数,如果您查看GraphQL::Schema::Subscription

def subscribe( attrs = )
...
end

def update( attrs =  )
...
end

您可以安全地删除:argument 并使用参数定义您的更新方法,这将解决问题。

def update( _attrs =  )
  # your logic here
end

【讨论】:

以上是关于无法使用 graphql-ruby 订阅进行简单广播的主要内容,如果未能解决你的问题,请参考以下文章

订阅号接广进阶教程(中篇)

向 graphql-ruby 实现添加多个过滤器

graphql-ruby:Int 不是定义的输入类型(在 $first 上)

订阅号接广教程(须知):以新榜为案例

使用 graphql-ruby 实现联合类型

如何使用 graphql-ruby 测试 GraphQL 模式?