Prior to this commit, the `GraphQlObservationInstrumentation` would
instrument the following operations:
* GraphQL requests
* GraphQL data fetching operations
In the case of batch loading operations, the instrumentation would
consider each load call as a separate data fetching operation. This
would significantly clutter recorded traces and would make it look like
"N+1 problems" would still be present.
This commit adds a new "graphql.dataloader" observation for such
operations and avoids recording data fetching observations when
`SelfDescribingDataFetcher` declare that they call batch loading
operations.
Closes gh-1034
Prior to this commit, the `SelfDescribingDataFetcher` would augment the
`DataFetcher` contract and provide more information about the data
fetcher itself.
This commit adds a new `isBatchLoading` method to indicate whether the
current data fetcher is using a `DataLoader` for fetching elements.
In Spring for GraphQL, this can typically happen if the method is
annotated with `@BatchMapping` or if the `@SchemaMapping` method as a
`DataLoader` parameter.
This change is required for instrumentation purposes: such data fetchers
should not be instrumented as data fetching operations, but instead
delegate to the `DataLoaderRegistry` being itself instrumented.
Closes gh-1176
This commit upgrades to GraphQL Java 23.0.
Because this new version brings in java-dataloader 4.0.0, this commit
also adapts to a breaking change there. `DataLoaderOptions` is now
immutable and calling setters on it will return a new instance.
As a result, this commit also changes the `BatchLoaderRegistry` to
customize the dataloader by consuming a `DataLoaderOptions.Builder`
instead of a `DataLoaderOptions` directly. This only breaks binary
compatibility as both `DataLoaderOptions` and `DataLoaderOptions.Builder`
have identical APIs.
Closes gh-1169
As of gh-1149, CANCEL signals are propagated from the transport request
up to reactive `DataFetcher`s. This efficiently cancels processing and
avoids spending resources when execution results won't be sent to the
client.
Prior to this commit, this would have no effect on non-reactive
`DataFetcher`s because they would still be executed. While we cannot
consistently cancel ongoing blocking operations, we can avoid further
processing and other `DataFetcher`s from being called by returning an
error result instead of the original result.
This commit updates the `ContextDataFetcherDecorator` to detect if the
request has been cancelled and return early a data fetcher result with a
`AbortExecutionException` error instead of the original result.
Closes gh-1153
This commit adds a new web interceptor that can be configured with a
specific duration. If the response is not produced within this timeline,
the interceptor sends a HTTP error status to the client (by default,
"REQUEST TIMEOUT" but this can be configured) and sends a CANCEL signal
upstream.
This CANCEL signal flows up to controller methods and maually registered
data fetchers, if they have a reactive return type. Processing will be
automatically aborted.
For other types of date fetchers, applications can retrieve a publisher
from the GraphQL context and get notified of cancellations.
Closes gh-450
Prior to this commit, a WebSocket/SSE client disconnecting from the data
stream would cause a CANCEL signal to be sent to upstream publishers.
This signal would flow from the transport layer up to the
`ExecutionGraphQlService`. Because the `GraphQL` engine itself relies on
`CompletableFuture`, the CANCEL signal would not flow through and
reactive data fetchers would not receive it. This means that costly
reactive operations would not be cancelled and this could cause write
failures as publishers would still produce values.
This commit adds at the service level a Reactor `Sink` to the
`GraphQLContext` that can be picked up by the
`ContextDataFetcherDecorator` when decorating reactive data fetchers.
This allows us to manually cancel publishers when the CANCEL signal is
received at the transport level.
Fixes gh-1149