dd-trace-java icon indicating copy to clipboard operation
dd-trace-java copied to clipboard

Using completedStage in GraphQL results in an error

Open matsudamper opened this issue 1 year ago • 2 comments

If you use CompletableFuture.completedFuture, there is no problem. Or, No problems occur when DataDogAgent is not loaded by javaagent.

class Test {
    fun test(
        id: Long,
        env: DataFetchingEnvironment,
    ): CompletionStage<DataFetcherResult<Test>> {
        return CompletableFuture.completedStage(
            DataFetcherResult.newResult<Test>()
                .data(Test())
                .localContext(TestLocalContext(id))
                .build(),
        )
    }
}
Caused by: java.lang.UnsupportedOperationException
	at java.base/java.util.concurrent.CompletableFuture$MinimalStage.isDone(CompletableFuture.java:2926)
	at datadog.trace.instrumentation.graphqljava.InstrumentedDataFetcher.get(InstrumentedDataFetcher.java:59)
	at graphql.execution.ExecutionStrategy.invokeDataFetcher(ExecutionStrategy.java:311)
	at graphql.execution.ExecutionStrategy.fetchField(ExecutionStrategy.java:287)
	at graphql.execution.ExecutionStrategy.resolveFieldWithInfo(ExecutionStrategy.java:213)
	at graphql.execution.AsyncExecutionStrategy.execute(AsyncExecutionStrategy.java:55)
	at graphql.execution.ExecutionStrategy.completeValueForObject(ExecutionStrategy.java:702)
	at graphql.execution.ExecutionStrategy.completeValue(ExecutionStrategy.java:484)
	at graphql.execution.ExecutionStrategy.completeField(ExecutionStrategy.java:435)
	at graphql.execution.ExecutionStrategy.lambda$resolveFieldWithInfo$1(ExecutionStrategy.java:215)
	at java.base/java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:646)
	at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510)
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1773)

Version

dd-java-agentt: 1.24.2 dd-trace-api: 1.24.2 graphql-java: 21.3 kotlin: 1.9.21

java --version

openjdk 17.0.9 2023-10-17 LTS
OpenJDK Runtime Environment Corretto-17.0.9.8.1 (build 17.0.9+8-LTS)
OpenJDK 64-Bit Server VM Corretto-17.0.9.8.1 (build 17.0.9+8-LTS, mixed mode, sharing)

matsudamper avatar Nov 28 '23 06:11 matsudamper

completedStage returns MinimalStage.

public static <U> CompletionStage<U> completedStage(U value) {
    return new MinimalStage<U>((value == null) ? NIL : value);
}

isDone is not supported.


/**
 * A subclass that just throws UOE for most non-CompletionStage methods.
 */
static final class MinimalStage<T> extends CompletableFuture<T> {
    /* ~~ */
    @Override public boolean isDone() {
        throw new UnsupportedOperationException(); }
}

https://github.com/DataDog/dd-trace-java/blob/0f2d96f0b4b00ee1b1eaf28c858a8db1007fd9bc/dd-java-agent/instrumentation/graphql-java-14.0/src/main/java/datadog/trace/instrumentation/graphqljava/InstrumentedDataFetcher.java#L59

Adding a MinimalStage if-else seems like a good..

matsudamper avatar Nov 28 '23 06:11 matsudamper

Thanks for the details about your issue @matsudamper ! It looks like your application is using graphql-java 21 which has recently upgraded from Java 8 to Java 11. MinimalStage does not exist as a feature of CompletableFuture until Java 9. Because our instrumentation for graphql is based on graphql-java 14 and Java 8, we did not implement any handling of MinimalStage. This will require us to implement additional support for handling MinimalStage for CompletableFuture and as a result this will be handled as a feature request.

nayeem-kamal avatar Nov 28 '23 15:11 nayeem-kamal