fix(subscription): handle missing DgsContext in subscription callbacks #2236
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Pull request checklist
Pull Request type
Changes in this PR
This PR fixes a
NullPointerExceptionthat occurs when using Apollo Federation subscription callbacks withApolloFederatedTracingHeaderForwarderenabled.Issue #2077
Problem
When using Apollo Router with Netflix DGS Framework for GraphQL subscriptions with HTTP callbacks, enabling
ApolloFederatedTracingHeaderForwardercauses:Root Cause
The issue is caused by an interceptor execution order problem:
CallbackWebGraphQLInterceptorruns atLOWEST_PRECEDENCE(designed to run LAST)GraphQLContextContributorInstrumentation.createState()is called BEFOREDgsWebFluxGraphQLInterceptorDgsContext.from(graphQLContext)before DgsContext has been added to GraphQL contextSolution
Add null-safe access to DgsContext for subscription callback scenarios:
DgsContext.fromOrNull()method - A safe accessor that returns null instead of throwing NPE when DgsContext is not presentGraphQLContextContributorInstrumentation- Use null-safe access to handle cases where DgsContext may not be initialized yetFiles Changed
graphql-dgs/src/main/kotlin/com/netflix/graphql/dgs/context/DgsContext.ktfromOrNull()companion method with KDoc documentationgraphql-dgs/src/main/kotlin/com/netflix/graphql/dgs/context/GraphQLContextContributorInstrumentation.ktDgsContext.fromOrNull()instead ofDgsContext.from()New test files:
graphql-dgs/src/test/kotlin/com/netflix/graphql/dgs/context/DgsContextTest.ktgraphql-dgs/src/test/kotlin/com/netflix/graphql/dgs/context/GraphQLContextContributorInstrumentationTest.ktBackwards Compatibility
This is a backwards-compatible bug fix:
DgsContext.from()still throws NPE when context missing (existing behavior preserved)DgsContext.fromOrNull()is a new method - no impact on existing coderequestDatagracefully, but implementations already use nullable typesAlternatives considered
Interceptor Order Coordination - Force
DgsWebFluxGraphQLInterceptorto run before subscription callback setup by setting@Order(Ordered.HIGHEST_PRECEDENCE). This was rejected as it may conflict with Apollo's design of running callback interceptor last.Lazy Instrumentation Initialization - Defer
GraphQLContextContributorInstrumentationlogic to a later phase. This was rejected as it requires larger refactoring and may break existing behavior.Try-catch wrapper - Wrap the
DgsContext.from()call in try-catch. This was rejected in favor of explicit null-safe API which is cleaner and more idiomatic.The chosen solution (null-safe accessor) is minimal, backwards compatible, and explicit about the constraint.