All Downloads are FREE. Search and download functionalities are using the official Maven repository.

graphql.execution.ExecutorServiceExecutionStrategy Maven / Gradle / Ivy

There is a newer version: 230521-nf-execution
Show newest version
package graphql.execution;

import graphql.ExecutionResult;
import graphql.ExecutionResultImpl;
import graphql.GraphQLException;
import graphql.PublicApi;
import graphql.execution.instrumentation.Instrumentation;
import graphql.execution.instrumentation.InstrumentationContext;
import graphql.execution.instrumentation.parameters.InstrumentationExecutionStrategyParameters;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

/**
 *
 * 

Deprecation Notice : This execution strategy does not support all of the graphql-java capabilities * such as data loader. Since its so easy to create a data fetcher that uses * {@link java.util.concurrent.CompletableFuture#supplyAsync(java.util.function.Supplier, java.util.concurrent.Executor)} * to make field fetching happen off thread we recommend that you use that instead of this class. This class * will be removed in a future version. *

* *

ExecutorServiceExecutionStrategy uses an {@link ExecutorService} to parallelize the resolve.

* * Due to the nature of {@link #execute(ExecutionContext, ExecutionStrategyParameters)} implementation, {@link ExecutorService} * MUST have the following 2 characteristics: *
    *
  • 1. The underlying {@link java.util.concurrent.ThreadPoolExecutor} MUST have a reasonable {@code maximumPoolSize} *
  • 2. The underlying {@link java.util.concurrent.ThreadPoolExecutor} SHALL NOT use its task queue. *
* *

Failure to follow 1. and 2. can result in a very large number of threads created or hanging. (deadlock)

* * See {@code graphql.execution.ExecutorServiceExecutionStrategyTest} for example usage. * * @deprecated Use {@link graphql.execution.AsyncExecutionStrategy} and {@link java.util.concurrent.CompletableFuture#supplyAsync(java.util.function.Supplier, java.util.concurrent.Executor)} * in your data fetchers instead. */ @PublicApi @Deprecated public class ExecutorServiceExecutionStrategy extends ExecutionStrategy { final ExecutorService executorService; public ExecutorServiceExecutionStrategy(ExecutorService executorService) { this(executorService, new SimpleDataFetcherExceptionHandler()); } public ExecutorServiceExecutionStrategy(ExecutorService executorService, DataFetcherExceptionHandler dataFetcherExceptionHandler) { super(dataFetcherExceptionHandler); this.executorService = executorService; } @Override public CompletableFuture execute(final ExecutionContext executionContext, final ExecutionStrategyParameters parameters) { if (executorService == null) { return new AsyncExecutionStrategy().execute(executionContext, parameters); } Instrumentation instrumentation = executionContext.getInstrumentation(); InstrumentationExecutionStrategyParameters instrumentationParameters = new InstrumentationExecutionStrategyParameters(executionContext, parameters); InstrumentationContext executionStrategyCtx = instrumentation.beginExecutionStrategy(instrumentationParameters); MergedSelectionSet fields = parameters.getFields(); Map>> futures = new LinkedHashMap<>(); for (String fieldName : fields.keySet()) { final MergedField currentField = fields.getSubField(fieldName); ResultPath fieldPath = parameters.getPath().segment(mkNameForPath(currentField)); ExecutionStrategyParameters newParameters = parameters .transform(builder -> builder.field(currentField).path(fieldPath)); Callable> resolveField = () -> resolveField(executionContext, newParameters); futures.put(fieldName, executorService.submit(resolveField)); } CompletableFuture overallResult = new CompletableFuture<>(); executionStrategyCtx.onDispatched(overallResult); try { Map results = new LinkedHashMap<>(); for (String fieldName : futures.keySet()) { ExecutionResult executionResult; try { executionResult = futures.get(fieldName).get().join(); } catch (CompletionException e) { if (e.getCause() instanceof NonNullableFieldWasNullException) { assertNonNullFieldPrecondition((NonNullableFieldWasNullException) e.getCause()); results = null; break; } else { throw e; } } results.put(fieldName, executionResult != null ? executionResult.getData() : null); } ExecutionResultImpl executionResult = new ExecutionResultImpl(results, executionContext.getErrors()); overallResult.complete(executionResult); overallResult = overallResult.whenComplete(executionStrategyCtx::onCompleted); return overallResult; } catch (InterruptedException | ExecutionException e) { executionStrategyCtx.onCompleted(null, e); throw new GraphQLException(e); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy