You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In #1149, we fixed the fact that reactive controllers were not getting cancel signals from the transport layer because the CompletableFuture part of the GraphQL engine was not communicating that information back to data fetchers. As of #450, Spring for GraphQL ships with a TimeoutWebGraphQlInterceptor that triggers a cancel signal if the GraphQL exchange exceeds a configured duration.
While that cancel signal will consistently abort the processing of all Publisher based data fetchers, this is not the case for other types of data fetchers. Currently, the ContextDataFetcherDecorator visits all registered data fetchers and wraps them to save/restore the context propagation. Wrapped data fetchers can return non-reactive types, and in this case there is not consistent way to cancel their execution right now.
There are existing solutions used by the community, but we're wondering how applicable they are in general. Thread.interrupt requires coordination unlike Thread.stop. In both cases, the data fetcher is probably using a blocking HTTP client or a database driver that themselves are scheduling work on a separate thread. Here, work will not be cancelled. Manually scheduling work with such a wrapper also creates other disadvantages: the data fetcher loses all current context (no traceId in logs, no security context) and there might be a significant performance degradation.
Because data fetching often happens in stages, we could consider a different solution where we check the current cancellation status before returning a resolved value. Instead of returning a value and triggering subsequent data fetchers, we could return an error and abort further execution. While this won't cancel the current stage of data fetching, this will prevent further processing.
The text was updated successfully, but these errors were encountered:
bclozel
changed the title
Abort non-reactive controller methods when GraphQL request is cancelled
Prevent further invocation of data fetchers when GraphQL request is cancelled
Apr 1, 2025
In #1149, we fixed the fact that reactive controllers were not getting cancel signals from the transport layer because the
CompletableFuture
part of the GraphQL engine was not communicating that information back to data fetchers. As of #450, Spring for GraphQL ships with aTimeoutWebGraphQlInterceptor
that triggers a cancel signal if the GraphQL exchange exceeds a configured duration.While that cancel signal will consistently abort the processing of all Publisher based data fetchers, this is not the case for other types of data fetchers. Currently, the
ContextDataFetcherDecorator
visits all registered data fetchers and wraps them to save/restore the context propagation. Wrapped data fetchers can return non-reactive types, and in this case there is not consistent way to cancel their execution right now.There are existing solutions used by the community, but we're wondering how applicable they are in general.
Thread.interrupt
requires coordination unlikeThread.stop
. In both cases, the data fetcher is probably using a blocking HTTP client or a database driver that themselves are scheduling work on a separate thread. Here, work will not be cancelled. Manually scheduling work with such a wrapper also creates other disadvantages: the data fetcher loses all current context (no traceId in logs, no security context) and there might be a significant performance degradation.Because data fetching often happens in stages, we could consider a different solution where we check the current cancellation status before returning a resolved value. Instead of returning a value and triggering subsequent data fetchers, we could return an error and abort further execution. While this won't cancel the current stage of data fetching, this will prevent further processing.
The text was updated successfully, but these errors were encountered: