NoContextChainedInstrumentation.java
package graphql.execution.instrumentation;
import graphql.ExecutionResult;
import graphql.PublicApi;
import graphql.execution.instrumentation.parameters.InstrumentationExecuteOperationParameters;
import graphql.execution.instrumentation.parameters.InstrumentationExecutionParameters;
import graphql.execution.instrumentation.parameters.InstrumentationExecutionStrategyParameters;
import graphql.execution.instrumentation.parameters.InstrumentationFieldCompleteParameters;
import graphql.execution.instrumentation.parameters.InstrumentationFieldFetchParameters;
import graphql.execution.instrumentation.parameters.InstrumentationFieldParameters;
import graphql.execution.instrumentation.parameters.InstrumentationValidationParameters;
import graphql.language.Document;
import graphql.validation.ValidationError;
import org.jspecify.annotations.Nullable;
import java.util.List;
import java.util.function.BiConsumer;
/**
* This version of {@link ChainedInstrumentation} will call a list of {@link Instrumentation}s
* but it will never back on the returned {@link InstrumentationContext} objects, hence it is only suitable to
* certain use cases.
*
* Only use this class if you are optimising for memory usage as scale. In most cases the {@link ChainedInstrumentation}
* will do the job required with all the instrumentation features used however some users require the fastest performance and lowest memory
* usage at scale and this class can be used.
*
* At scale, the fact that the graphql engine holds the {@link InstrumentationContext} objects in memory for a (relatively) long time
* (the length of the request or the length of a large field fetch) means that memory pressure can grow
* and objects move into longer tenure GC pools. Holding these contexts is also not necessary if the instrumentation never needs to know when a
* certain execution step finishes.
*
* The {@link InstrumentationContext} is used ot know when an execution step has completed, so instrumentations that do
* timings say need to use this callback mechanism. Putting such an instrumentation into {@link NoContextChainedInstrumentation} would
* be a mistake because no callback will occur. Therefore, use of this class is reserved for very specific us cases. You are fore-warned.
*
* This class never holds onto the returned {@link InstrumentationContext} objects and always returns null
* as itself.
*/
@PublicApi
public class NoContextChainedInstrumentation extends ChainedInstrumentation {
public NoContextChainedInstrumentation(List<Instrumentation> instrumentations) {
super(instrumentations);
}
public NoContextChainedInstrumentation(Instrumentation... instrumentations) {
super(instrumentations);
}
private <T> T runAll(InstrumentationState state, BiConsumer<Instrumentation, InstrumentationState> stateConsumer) {
chainedConsume(state, stateConsumer);
return null;
}
@Override
public InstrumentationContext<ExecutionResult> beginExecution(InstrumentationExecutionParameters parameters, InstrumentationState state) {
return runAll(state, (instrumentation, specificState) -> instrumentation.beginExecution(parameters, specificState));
}
@Override
public InstrumentationContext<Document> beginParse(InstrumentationExecutionParameters parameters, InstrumentationState state) {
return runAll(state, (instrumentation, specificState) -> instrumentation.beginParse(parameters, specificState));
}
@Override
public InstrumentationContext<List<ValidationError>> beginValidation(InstrumentationValidationParameters parameters, InstrumentationState state) {
return runAll(state, (instrumentation, specificState) -> instrumentation.beginValidation(parameters, specificState));
}
@Override
public InstrumentationContext<ExecutionResult> beginExecuteOperation(InstrumentationExecuteOperationParameters parameters, InstrumentationState state) {
return runAll(state, (instrumentation, specificState) -> instrumentation.beginExecuteOperation(parameters, specificState));
}
@Override
public ExecutionStrategyInstrumentationContext beginExecutionStrategy(InstrumentationExecutionStrategyParameters parameters, InstrumentationState state) {
return runAll(state, (instrumentation, specificState) -> instrumentation.beginExecutionStrategy(parameters, specificState));
}
@Override
public @Nullable ExecuteObjectInstrumentationContext beginExecuteObject(InstrumentationExecutionStrategyParameters parameters, InstrumentationState state) {
return runAll(state, (instrumentation, specificState) -> instrumentation.beginExecuteObject(parameters, specificState));
}
@Override
public InstrumentationContext<Object> beginDeferredField(InstrumentationFieldParameters parameters, InstrumentationState state) {
return runAll(state, (instrumentation, specificState) -> instrumentation.beginDeferredField(parameters, specificState));
}
@Override
public InstrumentationContext<ExecutionResult> beginSubscribedFieldEvent(InstrumentationFieldParameters parameters, InstrumentationState state) {
return runAll(state, (instrumentation, specificState) -> instrumentation.beginSubscribedFieldEvent(parameters, specificState));
}
@Override
public @Nullable InstrumentationContext<Object> beginFieldExecution(InstrumentationFieldParameters parameters, InstrumentationState state) {
return runAll(state, (instrumentation, specificState) -> instrumentation.beginFieldExecution(parameters, specificState));
}
@Override
public InstrumentationContext<Object> beginFieldFetch(InstrumentationFieldFetchParameters parameters, InstrumentationState state) {
return runAll(state, (instrumentation, specificState) -> instrumentation.beginFieldFetch(parameters, specificState));
}
@Override
public FieldFetchingInstrumentationContext beginFieldFetching(InstrumentationFieldFetchParameters parameters, InstrumentationState state) {
return runAll(state, (instrumentation, specificState) -> instrumentation.beginFieldFetching(parameters, specificState));
}
@Override
public @Nullable InstrumentationContext<Object> beginFieldCompletion(InstrumentationFieldCompleteParameters parameters, InstrumentationState state) {
return runAll(state, (instrumentation, specificState) -> instrumentation.beginFieldCompletion(parameters, specificState));
}
@Override
public @Nullable InstrumentationContext<Object> beginFieldListCompletion(InstrumentationFieldCompleteParameters parameters, InstrumentationState state) {
return runAll(state, (instrumentation, specificState) -> instrumentation.beginFieldListCompletion(parameters, specificState));
}
// relies on the other methods from ChainedInstrumentation which this does not change
}