Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
7694618
WIP: Created execution result classes for incremental delivery
felipe-gdr-atlassian Dec 20, 2023
ae52efd
Merge branch 'defer-support-in-enf' into defer-support-execution
felipe-gdr-atlassian Dec 20, 2023
acb00a5
Merge branch 'defer-support-in-enf' into defer-support-execution
felipe-gdr-atlassian Dec 20, 2023
7aa8c23
WIP
felipe-gdr-atlassian Jan 2, 2024
10b0499
Merge branch 'defer-support-in-enf' into defer-support-execution
felipe-gdr-atlassian Jan 8, 2024
0025495
WIP
felipe-gdr-atlassian Jan 8, 2024
b02efd8
Revert "WIP"
felipe-gdr-atlassian Jan 9, 2024
691d138
Merge branch 'defer-support-in-enf' into defer-support-execution
felipe-gdr-atlassian Jan 9, 2024
cbd9b63
Fixes on IncrementalItem hierarchy
felipe-gdr-atlassian Jan 10, 2024
40b7dfa
Merge branch 'master' into defer-support-execution
felipe-gdr-atlassian Jan 11, 2024
ceac689
Adjustments and plenty of Javadoc
felipe-gdr-atlassian Jan 11, 2024
a8f7906
Add unit test for sanity check
felipe-gdr-atlassian Jan 11, 2024
6b52b02
Fix Javadoc
felipe-gdr-atlassian Jan 11, 2024
d13b509
Minor adjustment in test class
felipe-gdr-atlassian Jan 11, 2024
291cfbf
Reverts both merge commits that deleted the old defer stuff.
felipe-gdr-atlassian Jan 12, 2024
c7088b1
Fix compilation errors
felipe-gdr-atlassian Jan 15, 2024
e86286e
WIP: hacky defer is working, some new tests for basic stuff, but a lo…
felipe-gdr-atlassian Jan 18, 2024
36d0330
Fixed a race condition and added more tests
felipe-gdr-atlassian Jan 19, 2024
348515d
Memoize field value resolution
felipe-gdr-atlassian Jan 19, 2024
ea9726a
Remove code
felipe-gdr-atlassian Jan 19, 2024
d03c8db
Remove unnecessary code and cover more edge cases
felipe-gdr-atlassian Jan 23, 2024
ca51dcb
Add more tests for DeferContext
felipe-gdr-atlassian Jan 23, 2024
85ac363
Create IncrementalCall interface and add type abstraction
felipe-gdr-atlassian Jan 23, 2024
1c60c37
Implement error handling in the defer execution code
felipe-gdr-atlassian Jan 25, 2024
276c872
Add one more test case
felipe-gdr-atlassian Jan 25, 2024
a5aa0fd
Add test for defer in list items
felipe-gdr-atlassian Jan 29, 2024
f43849f
Remove unnecessary test code
felipe-gdr-atlassian Jan 29, 2024
98554dc
Javadoc
felipe-gdr-atlassian Jan 29, 2024
ccb7e70
Refactor IncrementalUtils to remove duplicated code
felipe-gdr-atlassian Jan 29, 2024
e0540d9
WIP
felipe-gdr-atlassian Feb 1, 2024
f912440
Fix all unit tests and start cleaning up
felipe-gdr-atlassian Feb 2, 2024
28d98d4
Simplify instrumentation code for deferred field execution
felipe-gdr-atlassian Feb 2, 2024
8cc3d13
Merge branch 'master' into defer-execution-2024
felipe-gdr-atlassian Feb 2, 2024
07bd477
Rename some things defer -> incremental
felipe-gdr-atlassian Feb 2, 2024
934f88f
Remove code duplication
felipe-gdr-atlassian Feb 2, 2024
52de911
Various small adjustments in preparation to send the PR for review
felipe-gdr-atlassian Feb 2, 2024
f1e03a6
Remove unused import
felipe-gdr-atlassian Feb 2, 2024
ef671d0
PR feedback
felipe-gdr-atlassian Feb 5, 2024
32811eb
Merge branch 'master' into defer-execution-2024
felipe-gdr-atlassian Feb 6, 2024
c6d830c
Undo renaming to NormalizedDeferExecution: will be done in another PR
felipe-gdr-atlassian Feb 7, 2024
fe710a9
Undo refactoring around IncrementalNodes: will be done on future PR
felipe-gdr-atlassian Feb 7, 2024
61ca8d1
Refactoring method to receive individual parameters instead of object
felipe-gdr-atlassian Feb 7, 2024
864bf2e
Replace synchronized with runBlocked
felipe-gdr-atlassian Feb 7, 2024
4db2122
Fix groovy syntax
felipe-gdr-atlassian Feb 9, 2024
89e741d
Move gate mechanism from ExecutionInput to GraphQLContext
felipe-gdr-atlassian Feb 9, 2024
5900e9c
Rename DelayedIncrementalExecutionResult -> DelayedIncrementalPartial…
felipe-gdr-atlassian Feb 9, 2024
6fb8e74
(temporarily) Remove support for using Data loader to fetch deferred …
felipe-gdr-atlassian Feb 9, 2024
d87a6df
Rename DeferredCall -> DeferredFragmentCall
felipe-gdr-atlassian Feb 9, 2024
bfafd99
Move DeferredExecutionSupport into its own class file
felipe-gdr-atlassian Feb 9, 2024
e96eec5
Merge branch 'master' into defer-execution-2024
felipe-gdr-atlassian Feb 9, 2024
00a1862
Adjustments after merging
felipe-gdr-atlassian Feb 9, 2024
a801d20
Move ENABLE_INCREMENTAL_SUPPORT to @ExperimentalApi
felipe-gdr-atlassian Feb 12, 2024
99c5d0f
Remove unnecessary isEmpty check
felipe-gdr-atlassian Feb 12, 2024
b126baf
Add test with label having 'null' value
felipe-gdr-atlassian Feb 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Rename DeferredCall -> DeferredFragmentCall
  • Loading branch information
felipe-gdr-atlassian committed Feb 9, 2024
commit d87a6df1222655b6da540c3c468ed87b4c70b103
16 changes: 8 additions & 8 deletions src/main/java/graphql/execution/AsyncExecutionStrategy.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import graphql.ExecutionResult;
import graphql.GraphQLContext;
import graphql.PublicApi;
import graphql.execution.incremental.DeferredCall;
import graphql.execution.incremental.DeferredFragmentCall;
import graphql.execution.incremental.DeferredCallContext;
import graphql.execution.incremental.DeferredExecution;
import graphql.execution.incremental.IncrementalCall;
Expand Down Expand Up @@ -159,7 +159,7 @@ class DeferredExecutionSupportImpl implements DeferredExecutionSupport {
private final ExecutionStrategyParameters parameters;
private final ExecutionContext executionContext;
private final BiFunction<ExecutionContext, ExecutionStrategyParameters, CompletableFuture<FieldValueInfo>> resolveFieldWithInfoFn;
private final Map<String, Supplier<CompletableFuture<DeferredCall.FieldWithExecutionResult>>> dfCache = new HashMap<>();
private final Map<String, Supplier<CompletableFuture<DeferredFragmentCall.FieldWithExecutionResult>>> dfCache = new HashMap<>();

private DeferredExecutionSupportImpl(
MergedSelectionSet mergedSelectionSet,
Expand Down Expand Up @@ -207,28 +207,28 @@ public List<String> getNonDeferredFieldNames(List<String> allFieldNames) {
@Override
public Set<IncrementalCall<? extends IncrementalPayload>> createCalls() {
return deferredExecutionToFields.keySet().stream()
.map(this::createDeferredCall)
.map(this::createDeferredFragmentCall)
.collect(Collectors.toSet());
}

private DeferredCall createDeferredCall(DeferredExecution deferredExecution) {
private DeferredFragmentCall createDeferredFragmentCall(DeferredExecution deferredExecution) {
DeferredCallContext deferredCallContext = new DeferredCallContext();

List<MergedField> mergedFields = deferredExecutionToFields.get(deferredExecution);

List<Supplier<CompletableFuture<DeferredCall.FieldWithExecutionResult>>> calls = mergedFields.stream()
List<Supplier<CompletableFuture<DeferredFragmentCall.FieldWithExecutionResult>>> calls = mergedFields.stream()
.map(currentField -> this.createResultSupplier(currentField, deferredCallContext))
.collect(Collectors.toList());

return new DeferredCall(
return new DeferredFragmentCall(
deferredExecution.getLabel(),
this.parameters.getPath(),
calls,
deferredCallContext
);
}

private Supplier<CompletableFuture<DeferredCall.FieldWithExecutionResult>> createResultSupplier(
private Supplier<CompletableFuture<DeferredFragmentCall.FieldWithExecutionResult>> createResultSupplier(
MergedField currentField,
DeferredCallContext deferredCallContext
) {
Expand Down Expand Up @@ -266,7 +266,7 @@ private Supplier<CompletableFuture<DeferredCall.FieldWithExecutionResult>> creat

return executionResultCF
.thenApply(executionResult ->
new DeferredCall.FieldWithExecutionResult(currentField.getName(), executionResult)
new DeferredFragmentCall.FieldWithExecutionResult(currentField.getName(), executionResult)
);
}
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@
import java.util.concurrent.CopyOnWriteArrayList;

/**
* Contains data relevant to the execution of a {@link DeferredCall}.
* Contains data relevant to the execution of a {@link DeferredFragmentCall}.
* <p>
* The responsibilities of this class are similar to {@link graphql.execution.ExecutionContext}, but restricted to the
* execution of a deferred call (instead of the whole GraphQL execution like {@link graphql.execution.ExecutionContext}).
* <p>
* Some behaviours, like error capturing, need to be scoped to a single {@link DeferredCall}, because each defer payload
* Some behaviours, like error capturing, need to be scoped to a single {@link DeferredFragmentCall}, because each defer payload
* contains its own distinct list of errors.
*/
@Internal
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
* Will result on 1 instance of `DeferredCall`, containing calls for the 2 fields: "text" and "summary".
*/
@Internal
public class DeferredCall implements IncrementalCall<DeferPayload> {
public class DeferredFragmentCall implements IncrementalCall<DeferPayload> {
private final String label;

public ResultPath getPath() {
Expand All @@ -48,7 +48,7 @@ public ResultPath getPath() {
private final List<Supplier<CompletableFuture<FieldWithExecutionResult>>> calls;
private final DeferredCallContext deferredCallContext;

public DeferredCall(
public DeferredFragmentCall(
String label,
ResultPath path,
List<Supplier<CompletableFuture<FieldWithExecutionResult>>> calls,
Expand Down Expand Up @@ -77,7 +77,7 @@ public CompletableFuture<DeferPayload> invoke() {
/**
* Non-nullable errors need special treatment.
* When they happen, all the sibling fields will be ignored in the result. So as soon as one of the field calls
* throw this error, we can ignore the {@link ExecutionResult} from all the fields associated with this {@link DeferredCall}
* throw this error, we can ignore the {@link ExecutionResult} from all the fields associated with this {@link DeferredFragmentCall}
* and build a special {@link DeferPayload} that captures the details of the error.
*/
private DeferPayload handleNonNullableFieldError(DeferPayload result, Throwable throwable) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import graphql.ExecutionResultImpl
import graphql.GraphQLError
import graphql.execution.NonNullableFieldWasNullException
import graphql.execution.ResultPath
import graphql.execution.incremental.DeferredCall
import graphql.execution.incremental.DeferredCallContext
import spock.lang.Specification

import java.util.concurrent.CompletableFuture
Expand All @@ -18,7 +16,7 @@ class DeferredCallTest extends Specification {

def "test call capture gives a CF"() {
given:
DeferredCall call = new DeferredCall("my-label", parse("/path"),
DeferredFragmentCall call = new DeferredFragmentCall("my-label", parse("/path"),
[createResolvedFieldCall("field", "some data")], new DeferredCallContext())

when:
Expand All @@ -33,7 +31,7 @@ class DeferredCallTest extends Specification {

def "multiple field calls are resolved together"() {
given:
DeferredCall call = new DeferredCall("my-label", parse("/path"),
DeferredFragmentCall call = new DeferredFragmentCall("my-label", parse("/path"),
[
createResolvedFieldCall("field1", "some data 1"),
createResolvedFieldCall("field2", "some data 2"),
Expand All @@ -60,7 +58,7 @@ class DeferredCallTest extends Specification {
getPath() >> ResultPath.parse("/path")
}

DeferredCall call = new DeferredCall("my-label", parse("/path"), [
DeferredFragmentCall call = new DeferredFragmentCall("my-label", parse("/path"), [
createFieldCallThatThrowsException(mockedException),
createResolvedFieldCall("field1", "some data")
], deferredCallContext)
Expand All @@ -83,36 +81,36 @@ class DeferredCallTest extends Specification {
]
}

private static Supplier<CompletableFuture<DeferredCall.FieldWithExecutionResult>> createResolvedFieldCall(
private static Supplier<CompletableFuture<DeferredFragmentCall.FieldWithExecutionResult>> createResolvedFieldCall(
String fieldName,
Object data
) {
return createResolvedFieldCall(fieldName, data, Collections.emptyList())
}

private static Supplier<CompletableFuture<DeferredCall.FieldWithExecutionResult>> createResolvedFieldCall(
private static Supplier<CompletableFuture<DeferredFragmentCall.FieldWithExecutionResult>> createResolvedFieldCall(
String fieldName,
Object data,
List<GraphQLError> errors
) {
return new Supplier<CompletableFuture<DeferredCall.FieldWithExecutionResult>>() {
return new Supplier<CompletableFuture<DeferredFragmentCall.FieldWithExecutionResult>>() {
@Override
CompletableFuture<DeferredCall.FieldWithExecutionResult> get() {
CompletableFuture<DeferredFragmentCall.FieldWithExecutionResult> get() {
return completedFuture(
new DeferredCall.FieldWithExecutionResult(fieldName,
new DeferredFragmentCall.FieldWithExecutionResult(fieldName,
new ExecutionResultImpl(data, errors)
)
)
}
}
}

private static Supplier<CompletableFuture<DeferredCall.FieldWithExecutionResult>> createFieldCallThatThrowsException(
private static Supplier<CompletableFuture<DeferredFragmentCall.FieldWithExecutionResult>> createFieldCallThatThrowsException(
Throwable exception
) {
return new Supplier<CompletableFuture<DeferredCall.FieldWithExecutionResult>>() {
return new Supplier<CompletableFuture<DeferredFragmentCall.FieldWithExecutionResult>>() {
@Override
CompletableFuture<DeferredCall.FieldWithExecutionResult> get() {
CompletableFuture<DeferredFragmentCall.FieldWithExecutionResult> get() {
return CompletableFuture.failedFuture(exception)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,27 +142,27 @@ class IncrementalCallStateDeferTest extends Specification {

def "multiple fields are part of the same call"() {
given: "a DeferredCall that contains resolution of multiple fields"
def call1 = new Supplier<CompletableFuture<DeferredCall.FieldWithExecutionResult>>() {
def call1 = new Supplier<CompletableFuture<DeferredFragmentCall.FieldWithExecutionResult>>() {
@Override
CompletableFuture<DeferredCall.FieldWithExecutionResult> get() {
CompletableFuture<DeferredFragmentCall.FieldWithExecutionResult> get() {
return CompletableFuture.supplyAsync({
Thread.sleep(10)
new DeferredCall.FieldWithExecutionResult("call1", new ExecutionResultImpl("Call 1", []))
new DeferredFragmentCall.FieldWithExecutionResult("call1", new ExecutionResultImpl("Call 1", []))
})
}
}

def call2 = new Supplier<CompletableFuture<DeferredCall.FieldWithExecutionResult>>() {
def call2 = new Supplier<CompletableFuture<DeferredFragmentCall.FieldWithExecutionResult>>() {
@Override
CompletableFuture<DeferredCall.FieldWithExecutionResult> get() {
CompletableFuture<DeferredFragmentCall.FieldWithExecutionResult> get() {
return CompletableFuture.supplyAsync({
Thread.sleep(100)
new DeferredCall.FieldWithExecutionResult("call2", new ExecutionResultImpl("Call 2", []))
new DeferredFragmentCall.FieldWithExecutionResult("call2", new ExecutionResultImpl("Call 2", []))
})
}
}

def deferredCall = new DeferredCall(null, ResultPath.parse("/field/path"), [call1, call2], new DeferredCallContext())
def deferredCall = new DeferredFragmentCall(null, ResultPath.parse("/field/path"), [call1, call2], new DeferredCallContext())

when:
def incrementalCallState = new IncrementalCallState()
Expand Down Expand Up @@ -195,35 +195,35 @@ class IncrementalCallStateDeferTest extends Specification {
results.any { it.incremental[0].data["c"] == "C" }
}

private static DeferredCall offThread(String data, int sleepTime, String path) {
def callSupplier = new Supplier<CompletableFuture<DeferredCall.FieldWithExecutionResult>>() {
private static DeferredFragmentCall offThread(String data, int sleepTime, String path) {
def callSupplier = new Supplier<CompletableFuture<DeferredFragmentCall.FieldWithExecutionResult>>() {
@Override
CompletableFuture<DeferredCall.FieldWithExecutionResult> get() {
CompletableFuture<DeferredFragmentCall.FieldWithExecutionResult> get() {
return CompletableFuture.supplyAsync({
Thread.sleep(sleepTime)
if (data == "Bang") {
throw new RuntimeException(data)
}
new DeferredCall.FieldWithExecutionResult(data.toLowerCase(), new ExecutionResultImpl(data, []))
new DeferredFragmentCall.FieldWithExecutionResult(data.toLowerCase(), new ExecutionResultImpl(data, []))
})
}
}

return new DeferredCall(null, ResultPath.parse(path), [callSupplier], new DeferredCallContext())
return new DeferredFragmentCall(null, ResultPath.parse(path), [callSupplier], new DeferredCallContext())
}

private static DeferredCall offThreadCallWithinCall(IncrementalCallState incrementalCallState, String dataParent, String dataChild, int sleepTime, String path) {
def callSupplier = new Supplier<CompletableFuture<DeferredCall.FieldWithExecutionResult>>() {
private static DeferredFragmentCall offThreadCallWithinCall(IncrementalCallState incrementalCallState, String dataParent, String dataChild, int sleepTime, String path) {
def callSupplier = new Supplier<CompletableFuture<DeferredFragmentCall.FieldWithExecutionResult>>() {
@Override
CompletableFuture<DeferredCall.FieldWithExecutionResult> get() {
CompletableFuture<DeferredFragmentCall.FieldWithExecutionResult> get() {
CompletableFuture.supplyAsync({
Thread.sleep(sleepTime)
incrementalCallState.enqueue(offThread(dataChild, sleepTime, path))
new DeferredCall.FieldWithExecutionResult(dataParent.toLowerCase(), new ExecutionResultImpl(dataParent, []))
new DeferredFragmentCall.FieldWithExecutionResult(dataParent.toLowerCase(), new ExecutionResultImpl(dataParent, []))
})
}
}
return new DeferredCall(null, ResultPath.parse("/field/path"), [callSupplier], new DeferredCallContext())
return new DeferredFragmentCall(null, ResultPath.parse("/field/path"), [callSupplier], new DeferredCallContext())
}

private static void assertResultsSizeAndHasNextRule(int expectedSize, List<DelayedIncrementalPartialResult> results) {
Expand Down