这是indexloc提供的服务,不要输入任何密码
Skip to content

support graphql-ws protocol #67

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jan 18, 2023
Merged

support graphql-ws protocol #67

merged 9 commits into from
Jan 18, 2023

Conversation

hgiasac
Copy link

@hgiasac hgiasac commented Jan 16, 2023

close #38

Support graphql-ws protocol. By default, the subscription client still uses subscriptions-transport-ws protocol for backward compatibility. Configures with the WithProtocol function the graphql-ws protocol,

client := graphql.NewSubscriptionClient("ws://localhost:8080/v1/graphql").
    WithProtocol(graphql.GraphQLWS)

The client works well with Hasura graphql engine (example)

@hgiasac hgiasac marked this pull request as ready for review January 18, 2023 10:48
@hgiasac hgiasac merged commit 1265577 into master Jan 18, 2023
@hgiasac hgiasac deleted the support-graphql-ws-protocol branch January 18, 2023 11:13
@@ -446,66 +551,16 @@ func (sc *SubscriptionClient) Run() error {

if sc.onError != nil {
if err = sc.onError(sc, err); err != nil {
// end the subscription if the callback return error
Copy link

@sermojohn sermojohn Feb 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I visited this PR after looking up an issue with an earlier version of this library (v0.6.4). When an error is raised and it ends up in this branch, the connection is not reset, so any retry attempt to use subscriptionClient.Run is not effective. In that case, we would need to explicitly Reset() the subscriptionClient, so it can be reused.

In this PR, I can see that Close() is called when this point is reached, so the subscriptionClient cannot be reused, by consuming the error from Run() and recalling Run().
Is this change intentional, cause this changes the behaviour of the subscriptionClient quite significantly IMO?

UPDATE: the above statement was incorrect, so it seems that the subscriptionClient can indeed be reused multiple times, by calling Run -> Close -> Run -> Close, is this correct?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The onError line is explained in the document https://github.com/hasura/go-graphql-client#handle-connection-error. It's intentional. The subscription client tries to retry subscriptions if the GraphQL server is outage (disconnected). For user-defined errors, we should let the user decide whether to end the subscription.

The Close method clears all subscriptions and closes the WebSocket connection. In theory you can continue to Run the subscription client after being Close. However, you need to resubscribe subscriptions. It's better to use Reset function which resets subscription states and runs a new WebSocket connection

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, thanks for your answer!

So, in case a user-defined error is raised how can the user perform a retry? It seems the OnError should consume the error and return nil, so the client is not closed. Is it suggested to call the Reset in the OnError function? Sorry, its not crystal-clear to me from the documentation, although this might be the reason for providing the subscriptionClient instance in the callback.

Also, what if the user of the library applies its own retry-mechanism to the client, and still tries to reuse the client?

It seems to me its now impossible to properly decide if the retry should call Run or Reset because if the client failed in the initialisation phase, then Run should be executed, while Reset is only useful after the client has initialised at least once. This information is held by isRunning which is internal, so the user cannot make a proper decision if Run or Reset should be called.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems to me that the current version of Reset can replace Run because it is actually a superset (not an intersection) of what Run does, so it can be called multiple times (idempotent) while the state of the subscription client defines what actions will be triggered. This could also simplify the the public interface of the subscription client by removing Reset in favour of Run. What do you think?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense. Anyway, the client should handle the retry mechanism when there is some connection problem only. For other errors, the client should stop and let developers rerun subscriptions themselves. We shouldn't force retrying for every error because it will lead to an endless loop.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change is updated here #76. Feel free to leave some feedback. Thanks!

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I am glad to provide review/feedback!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

implement graphql-ws protocol
2 participants