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
Implement callback subscription protocol in new plugin ApolloServerPluginSubscriptionCallback
#7617
Conversation
✅ Deploy Preview for apollo-server-docs ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
This pull request is automatically built and testable in CodeSandbox. To see build info of the built libraries, click here or the icon next to each commit SHA. Latest deployment of this branch, based on commit c7885c8:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I took a quick initial glance and have some high level questions, but I think I'll need to learn more about the details of the subscription callback protocol before doing more of a review.
0f1bde6
to
7bd798a
Compare
return; | ||
} | ||
|
||
// The `check` request was successful, so we can initialize the actual |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you want to check the uniqueness of the subscription ids before you subscribe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually I guess the router probably already does that for you?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wouldn't expect the router to send duplicates but I suppose it could, are you suggesting defending against that (maybe by checking to see if we're already subscribed on that id in the SubscriptionManager
)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess I was thinking about a client that was generating non-unique subscription ids.
self.logger?.debug('`next` request successful', id); | ||
} catch (e) { | ||
self.logger?.error(`\`next\` request failed: ${e}`, id); | ||
// TODO: handle this error (terminate subscription / retry?) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could fail due to a transient error, right? I'm not sure what the spec says about guaranteed delivery vs. ordering trade off, but I wouldn't think we'd want to throw the first time there's an error.
1294b14
to
191e4d0
Compare
67a7335
to
0cdceda
Compare
0cdceda
to
5ab55aa
Compare
packages/server/src/__tests__/plugin/subscriptionCallback/index.test.ts
Outdated
Show resolved
Hide resolved
packages/server/src/__tests__/plugin/subscriptionCallback/index.test.ts
Outdated
Show resolved
Hide resolved
@clenfest I wrapped the other request types with the retry lib as well. There's almost a good abstraction to be made there but there is the one special case for Update: pretty happy with the outcome in c7885c8, but the diff is really awful. Looks like git found a bit too much similarity in 2 different functions and clobbered it. |
a573c69
to
c42ec16
Compare
c42ec16
to
c7885c8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated. # Releases ## @apollo/server@4.9.0 ### Minor Changes - [#7617](#7617) [`4ff81ca50`](4ff81ca) Thanks [@trevor-scheer](https://github.com/trevor-scheer)! - Introduce new `ApolloServerPluginSubscriptionCallback` plugin. This plugin implements the [subscription callback protocol](https://github.com/apollographql/router/blob/dev/dev-docs/callback_protocol.md) which is used by Apollo Router. This feature implements subscriptions over HTTP via a callback URL which Apollo Router registers with Apollo Server. This feature is currently in preview and is subject to change. You can enable callback subscriptions like so: ```ts import { ApolloServerPluginSubscriptionCallback } from '@apollo/server/plugin/subscriptionCallback'; import { ApolloServer } from '@apollo/server'; const server = new ApolloServer({ // ... plugins: [ApolloServerPluginSubscriptionCallback()], }); ``` Note that there is currently no tracing or metrics mechanism in place for callback subscriptions. Additionally, this plugin "intercepts" callback subscription requests and bypasses some of Apollo Server's internals. The result of this is that certain plugin hooks (notably `executionDidStart` and `willResolveField`) will not be called when handling callback subscription requests or when sending subscription events. For more information on the subscription callback protocol, visit the docs: <https://www.apollographql.com/docs/router/executing-operations/subscription-callback-protocol/> ### Patch Changes - [#7659](#7659) [`4784f46fb`](4784f46) Thanks [@renovate](https://github.com/apps/renovate)! - Update graphql-http dependency ## @apollo/server-integration-testsuite@4.9.0 ### Patch Changes - [#7659](#7659) [`4784f46fb`](4784f46) Thanks [@renovate](https://github.com/apps/renovate)! - Update graphql-http dependency - Updated dependencies \[[`4ff81ca50`](4ff81ca), [`4784f46fb`](4784f46)]: - @apollo/server@4.9.0 Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
I have a small question regarding the subscription completion. The emitter notifies the router about completion using the |
Hi @enisdenjo, it's nice to meet you! When a subgraph sends a payload to the router, the router will use the http status_code to indicate the emitter some or all clients unsubscribed. The error-states section of the docs, and the heartbeat answer provide details as to what to expect. Hope it helps! |
Hey there @o0Ignition0o, nice to meet you too! Thanks for the explanation and the links, they were very helpful. I have the complete picture now! |
This PR creates a new plugin for Apollo Server which implements the new subscription callback protocol.
While the plugin approach works, it does have a couple notable pitfalls. I see this as a good first step towards enabling people to use it today. The nature of this implementation is to skip execution in Apollo Server altogether, which means the execution internals are bypassed. This means that some plugin hooks are skipped - notably
executionDidStart/End
andwillResolveField
(for field-level instrumentation) when resolving these types of operations.Fortunately, most of the logic is captured in the
SubscriptionManager
class. The plugin mostly just wraps it, and Apollo Server should be able to integrate it when we choose to.