NPM
I am scratching my head trying to understand how to implement a subscription.
http://graphql-ruby.org/subscriptions/subscription_type.html

It says define a field like above, but the field actually needs a corresponding method like this. (otherwise it shows errors)
def post_was_published
# ...
end
and just the below the code, it says This will be called on the initial request

But as far as I checked, this method will be called
Plus, even if I have a return value written in the method, it will not be sent to the client, but the triggered object value will be sent.
def post_was_published
Post.first # this will never be sent to the client on either initial or trigger
end
```rb
Schema.subscriptions.trigger("postWasPublished", {}, Post.last) # this Post.last will be sent
Here are what I am trying to figure out.
1. The SubscriptionType method is being called on initial and trigger call, shouldn't it be just on initial?
1. The return value in the SubscriptionType method won't be sent to the client, I shouldn't return any values?
1. Should I just have a job call (like sidekiq perform_async which calls `Schema.subscriptions.trigger`) in the method?, but the method is called on trigger as well, that will make a loop
ex:
```rb
def post_was_published
SidekiqJob.perform_async # this will do the trigger call
end
I am not sure if this is a legit way, but only difference I could see between initial and trigger calls was the context variable in the method.
https://github.com/rmosolgo/graphql-ruby/blob/b58bdac2d42e036788f6faa9799de11261c25582/lib/graphql/subscriptions/action_cable_subscriptions.rb#L115
On trigger, context has a key called :subscription_id, but initial call doesn't.
So I used the key to define if a call is initial one, like this.
https://github.com/github0013/graphql_subscription_actioncable/commit/55f5069e75c4c06670d5111b0360f08e6d297c16
I think I'm struggling with something very similar. I've been wracking my brain and combing the source trying to figure out what I'm missing, but I can't figure out why the object argument to Schema.subscriptions.trigger is always the result of the reloaded query.
My current setup involves a simple subscription for tracking the progress of an ActiveJob-powered upload task:
# graphql/subscriptions/upload_progress.rb
module Subscriptions
class UploadProgress < ApplicationResolver
description 'Stream progress from an ongoing upload.'
type Types::UploadProgress, null: false
argument :job, ID, required: true
def resolve(job:)
message = Sidekiq::Status.message(job)
percent_complete = Sidekiq::Status.pct_complete(job)
status = Sidekiq::Status.status(job)
{ message: message, percent_complete: percent_complete, status: status }
end
end
end
# graphql/types/subscription.rb
module Types
class Subscription < ApplicationObject
field :upload_progress, resolver: Subscriptions::UploadProgress
end
end
I've set up ActionCable and graphql-ruby-client in the frontend and I've implemented a quick-'n'-dirty Redis backing for subscriptions (which you can gut-check here if you're so inclined) so that they're shared between ActiveJob jobs and the ActionCable server. I can trigger events and the client will respond to them.
The perplexing thing is that when I call trigger, I have to pass the full payload for UploadProgress as the object. This works, e.g.:
Schema.subscriptions.trigger(:upload_progress, { job: @provider_job_id }, message: message, percent_complete: percent_complete, status: status)
...whereas this fails with an InvalidNullError ("Cannot return null for non-nullable field Subscription.uploadProgress"):
Schema.subscriptions.trigger(:upload_progress, { job: @provider_job_id }, nil)
...and this fails with a slightly different InvalidNullError ("Cannot return null for non-nullable field UploadProgress.percentComplete"):
Schema.subscriptions.trigger(:upload_progress, { job: @provider_job_id }, {})
...and so on.
Except that I'm never returning null for UploadProgress; I'm only passing a nil for the root value. I confirmed this to my satisfaction by Prying into the resolver method while the query was being refreshed; Pry showed that I received the same argument I passed in, successfully resolved the status information, and returned a Hash:
Frame number: 0/156
From: /Users/daniel/Repos/Ignota/structur-api/app/graphql/subscriptions/upload_progress.rb @ line 16 Subscriptions::UploadProgress#resolve:
11: def resolve(job:)
12: message = Sidekiq::Status.message(job)
13: percent_complete = Sidekiq::Status.pct_complete(job)
14: status = Sidekiq::Status.status(job)
15:
=> 16: binding.pry
17:
18: { message: message, percent_complete: percent_complete, status: status }
19: end
@arguments_by_keyword {:job=>#<GraphQL::Schema::Argument:0x00007f9463be33a0 @name="job", @type_expr="ID", @description=nil, @null=false, @default_value=:__no_default__, @owner=Subscriptions::UploadProgress, @as=nil, @keyword=:job, @prepare=nil, @type=#<GraphQL::Schema::NonNull:0x00007f946a933c98 @of_type=GraphQL::Types::ID, @graphql_definition=ID!>>}
@arguments_loads_as_type {}
@context #<Query::Context ...>
@object nil
job "9e70ccbb20c1395175c95c7d"
message "Transcoding MP4..."
percent_complete 0
status :working
If the maintainers have any insight into what's going on here, I'd be grateful for some guidance. Why is the object filtering back down to the client, and where are these null checks misfiring?
Thanks in advance for your thoughts! 馃檹
/cc @rmosolgo
Trying to cover this in #1930
Amazing! Looking forward to following that PR, happy to provide support or color if I can in any way.
Hi, I hope class-based subscriptions helped with this! Please give them a try and open an issue if you run into any trouble.
Most helpful comment
Trying to cover this in #1930