actioncablegraphql-subscriptionsgraphql-ruby

Can't get a simple broadcast with graphql-ruby subscriptions working


I have a barebones setup for update broadcasts with graphql-ruby over Action Cable.

The docs I'm looking at:

The subscription type:

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

The way I'm attempting to trigger an update:

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

The schema is defined as:

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

  subscription(Types::SubscriptionType)
end

I am using the redis adapter for the development environment in config/cable.yml:

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

What am I missing? Any troubleshooting tips?

Update:

Some diagnostics:

Rails logs for the initial (and successful) subscription call:

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

Checking active Redis PubSub channels:

$ 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"

Outcome of running the trigger call in the Rails console:

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\"]}"

The thing that stands out as obvious is that the Redis PubSub channel is called "graphql-event::dateTime:" while the trigger call broadcasts over the nonexistent "graphql-event::serverInfo:" channel. I do not understand why the actual Redis channel is called "graphql-event::dateTime" while the subscription query is on the top-level "ServerInfo" type.


Solution

  • I finally got it working, but couldn't pinpoint why this wasn't working:

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

    Note that I had been passing an empty hash ({}) as the second argument.

    The way I got it working is to add an argument to my query and use a matching argument (matching to the original subscription query). Something like this:

    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' }
    )
    

    The Redis channel I can now see is:

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