Conversation
There was a problem hiding this comment.
Pull Request Overview
This PR adds a counter to the ExecutionContext to track whether the engine is running. The key changes include:
- Introducing an AtomicInteger (isRunning) with corresponding running() and finished() methods in ExecutionContext.
- Inserting calls to executionContext.running() and executionContext.finished() across various execution strategy classes.
- Ensuring that the execution state is tracked consistently during asynchronous execution.
Reviewed Changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/main/java/graphql/execution/SubscriptionExecutionStrategy.java | Inserts running/finished calls in the subscription strategy; includes an unnecessary semicolon that can be cleaned up. |
| src/main/java/graphql/execution/ExecutionStrategy.java | Adds running/finished calls to track execution state in object and field resolution flows. |
| src/main/java/graphql/execution/ExecutionContext.java | Introduces the AtomicInteger counter and its helper methods for tracking execution state. |
| src/main/java/graphql/execution/AsyncSerialExecutionStrategy.java | Adds running/finished calls around asynchronous field resolution. |
| src/main/java/graphql/execution/AsyncExecutionStrategy.java | Integrates running/finished calls to manage execution state during asynchronous execution. |
| src/main/java/graphql/execution/AbstractAsyncExecutionStrategy.java | Wraps up asynchronous result handling with running/finished calls. |
src/main/java/graphql/execution/SubscriptionExecutionStrategy.java
Outdated
Show resolved
Hide resolved
| @Override | ||
| public CompletableFuture<ExecutionResult> execute(ExecutionContext executionContext, ExecutionStrategyParameters parameters) throws NonNullableFieldWasNullException { | ||
|
|
||
| executionContext.running(); |
There was a problem hiding this comment.
Consider wrapping the code following executionContext.running() in a try-finally block to guarantee that executionContext.finished() is always called, ensuring the counter remains balanced even if exceptions occur.
| executionStrategyCtx.onDispatched(); | ||
|
|
||
| futures.await().whenComplete((completeValueInfos, throwable) -> { | ||
| executionContext.running(); |
There was a problem hiding this comment.
The repeated pattern of invoking executionContext.running() followed by executionContext.finished() could benefit from a refactoring (e.g. using try-finally constructs) to avoid potential imbalances in the counter during asynchronous processing.
Test Results 313 files 313 suites 47s ⏱️ Results for commit 339f657. ♻️ This comment has been updated with latest results. |
…java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
| @@ -60,11 +62,13 @@ public CompletableFuture<ExecutionResult> execute(ExecutionContext executionCont | |||
| executionStrategyCtx.onDispatched(); | |||
|
|
|||
| futures.await().whenComplete((completeValueInfos, throwable) -> { | |||
There was a problem hiding this comment.
Is this missing a executionContext.finished() before the .await() ??
| @@ -75,17 +79,21 @@ public CompletableFuture<ExecutionResult> execute(ExecutionContext executionCont | |||
| dataLoaderDispatcherStrategy.executionStrategyOnFieldValuesInfo(completeValueInfos); | |||
| executionStrategyCtx.onFieldValuesInfo(completeValueInfos); | |||
| fieldValuesFutures.await().whenComplete(handleResultsConsumer); | |||
There was a problem hiding this comment.
executionContext.finished() before the .await() ??
| executionContext.finished(); | ||
| return CompletableFuture.completedFuture(isNotSensible.get()); | ||
| } | ||
|
|
There was a problem hiding this comment.
executionContext.finished() before the Async.eachSequentially ?
| Async.CombinedBuilder<Object> resultFutures = fieldValuesCombinedBuilder(completeValueInfos); | ||
| dataLoaderDispatcherStrategy.executeObjectOnFieldValuesInfo(completeValueInfos, parameters); | ||
| resolveObjectCtx.onFieldValuesInfo(completeValueInfos); | ||
| resultFutures.await().whenComplete(handleResultsConsumer); |
There was a problem hiding this comment.
.await() - should this have a executionContext.finished() before it
There was a problem hiding this comment.
imagine this
instead of
executionContext.finished();
resultFutures.await().whenComplete(handleResultsConsumer);
we have helper method in the engine code
awaiting(executionContext, resultFutures.await())
and in that helper method it can
- call .finished()
- know when the CF returns and turn itself back on
| @@ -69,19 +69,24 @@ public CompletableFuture<ExecutionResult> execute(ExecutionContext executionCont | |||
| // | |||
| // when the upstream source event stream completes, subscribe to it and wire in our adapter | |||
| CompletableFuture<ExecutionResult> overallResult = sourceEventStream.thenApply((publisher) -> { | |||
There was a problem hiding this comment.
Do we need to turn this off here ??
| executionContext.running(); | ||
| Object publisher = fetchedValue.getFetchedValue(); | ||
| if (publisher != null) { | ||
| assertTrue(publisher instanceof Publisher, () -> "Your data fetcher must return a Publisher of events when using graphql subscriptions"); |
There was a problem hiding this comment.
If this threw an exception - we would still be running
| isRunning.incrementAndGet(); | ||
| try { | ||
| return callable.call(); | ||
| } catch (Exception e) { |
There was a problem hiding this comment.
why catch Exception - this seems wrong.
A GraphqlAbort exception for example will be wrapped in RuntimeException and its meaning lost
Ahh Callable throws exception - perhaps make a RuntimeCallable class instead
| try { | ||
| runnable.run(); | ||
| ; | ||
| } catch (Exception e) { |
There was a problem hiding this comment.
Runnable does not throw exceptions - so dont catch it
| } | ||
|
|
||
| @Nullable | ||
| EngineRunningObserver getEngineRunningObserver() { |
| import static graphql.collect.ImmutableKit.emptyList; | ||
|
|
||
| @PublicApi | ||
| @Internal |
adding a counter to ExecutionContext that tracks if the engine is running
Contains a small breaking change: it makes the ExecutionContext builder non public. I think nobody should create ExecutionContexts outside GraphLQ Java.