Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exception and stracktrace are useless when getting a SmallRye GraphQL Client error #45727

Open
gsmet opened this issue Jan 20, 2025 · 7 comments

Comments

@gsmet
Copy link
Member

gsmet commented Jan 20, 2025

Description

I'm getting a timeout for a GraphQL request executed on GitHub and I end up with the following:

io.smallrye.graphql.client.InvalidResponseException: Unexpected response. Code=504, message="Gateway Timeout", body="<!DOCTYPE html>

HTML of GitHub error page

at io.smallrye.graphql.client.impl.ResponseReader.readFrom(ResponseReader.java:80)
	at io.smallrye.graphql.client.vertx.dynamic.VertxDynamicGraphQLClient.lambda$executeSingleResultOperationOverHttp$10(VertxDynamicGraphQLClient.java:451)
	at io.smallrye.context.impl.wrappers.SlowContextualFunction.apply(SlowContextualFunction.java:21)
	at io.smallrye.mutiny.operators.uni.UniOnItemTransform$UniOnItemTransformProcessor.onItem(UniOnItemTransform.java:36)
	at io.smallrye.mutiny.operators.uni.builders.UniCreateFromCompletionStage$CompletionStageUniSubscription.forwardResult(UniCreateFromCompletionStage.java:63)
	at io.smallrye.context.impl.wrappers.SlowContextualBiConsumer.accept(SlowContextualBiConsumer.java:21)
	at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:863)
	at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:841)
	at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510)
	at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2179)
	at io.vertx.core.Future.lambda$toCompletionStage$3(Future.java:602)
	at io.vertx.core.impl.future.FutureImpl$4.onSuccess(FutureImpl.java:176)
	at io.vertx.core.impl.future.FutureBase.emitSuccess(FutureBase.java:66)
	at io.vertx.core.impl.future.FutureImpl.tryComplete(FutureImpl.java:259)
	at io.vertx.core.impl.future.PromiseImpl.onSuccess(PromiseImpl.java:49)
	at io.vertx.core.impl.future.PromiseImpl.handle(PromiseImpl.java:41)
	at io.vertx.core.impl.future.PromiseImpl.handle(PromiseImpl.java:23)
	at io.vertx.ext.web.client.impl.HttpContext.handleDispatchResponse(HttpContext.java:402)
	at io.vertx.ext.web.client.impl.HttpContext.execute(HttpContext.java:384)
	at io.vertx.ext.web.client.impl.HttpContext.next(HttpContext.java:362)
	at io.vertx.ext.web.client.impl.HttpContext.fire(HttpContext.java:329)
	at io.vertx.ext.web.client.impl.HttpContext.dispatchResponse(HttpContext.java:291)
	at io.vertx.ext.web.client.impl.HttpContext.lambda$null$7(HttpContext.java:512)
	at io.vertx.core.impl.ContextInternal.dispatch(ContextInternal.java:270)
	at io.vertx.core.impl.ContextInternal.dispatch(ContextInternal.java:252)
	at io.vertx.core.impl.ContextInternal.lambda$runOnContext$0(ContextInternal.java:50)
	at io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:173)
	at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:166)
	at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:566)
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:1583)

Note the stracktrace with absolutely no user code, nor any reference to the query.

Thus I have absolutely no idea which query is causing the issue, which is kind of a bummer.

Any chance we could improve this?

Implementation ideas

No response

Copy link

quarkus-bot bot commented Jan 20, 2025

/cc @Ladicek (smallrye), @brunobat (opentelemetry), @jmartisk (graphql,smallrye), @phillip-kruger (graphql,smallrye), @radcortez (opentelemetry,smallrye)

@jmartisk
Copy link
Contributor

jmartisk commented Jan 21, 2025

Do you also see Mutiny had to drop the following exception?

If you don't get the application part of the stack trace, I think the only way this can happen is that your app runs the operation asynchronously (client.executeAsync()) and does not register an onFailureCallback. If you were calling it synchronously or calling await() to wait for the result, or you registered an onFailureCallback, the exception would bubble up to application classes and it would be seen in the stack traces. Any chance you can find the relevant piece of code even without the stack trace? :)

@gsmet
Copy link
Member Author

gsmet commented Jan 21, 2025

I got the error with status.quarkus.io and it was reproducible always. You will have to revert this change though: quarkusio/status.quarkus.io#203 to be able to reproduce it.

See the setup instructions there: https://github.com/quarkusio/status.quarkus.io?tab=readme-ov-file#setup .

The code is the code in there: https://github.com/quarkusio/status.quarkus.io/blob/main/src/main/java/io/quarkus/status/github/GitHubService.java .

And all the calls are sync, not async.

@jmartisk
Copy link
Contributor

Ok I was able to reproduce it and it will need a slight change in smallrye-graphql, stay tuned.

@jmartisk
Copy link
Contributor

Actually, I am not yet sure how to best do this. The InvalidResponseException is an unchecked exception that happens inside a map operation in the Mutiny pipeline, so when it happens, the stack trace that referred to the original application code that triggered the pipeline is lost. See smallrye/smallrye-mutiny#1690

@jmartisk
Copy link
Contributor

I can fix it for your use case (with synchronous operations) by moving the throwing of InvalidResponseException into an imperative piece of code after performing an .await() for the server response. But it would be just a partial fix, because in the asynchronous case, I have to continue parsing the response inside the Mutiny pipeline.

@jmartisk
Copy link
Contributor

I've submitted smallrye/smallrye-graphql#2258, it seems to work for sync operations. With that applied, I am getting

io.smallrye.graphql.client.InvalidResponseException: Unexpected response. Code=504, message="Gateway Timeout", body="
<the html response>
"

	at io.smallrye.graphql.client.impl.ResponseReader.readFrom(ResponseReader.java:83)
	at io.smallrye.graphql.client.vertx.dynamic.VertxDynamicGraphQLClient.toResponse(VertxDynamicGraphQLClient.java:457)
	at io.smallrye.graphql.client.vertx.dynamic.VertxDynamicGraphQLClient.executeSync(VertxDynamicGraphQLClient.java:217)
	at io.smallrye.graphql.client.vertx.dynamic.VertxDynamicGraphQLClient.executeSync(VertxDynamicGraphQLClient.java:166)
	at io.quarkus.status.github.GitHubService.findIssuesByLabel(GitHubService.java:165)
	at io.quarkus.status.github.GitHubService_ClientProxy.findIssuesByLabel(Unknown Source)
	at io.quarkus.status.StatusService.buildStatus(StatusService.java:98)
	at io.quarkus.status.StatusService.updateStatus(StatusService.java:54)
	at io.quarkus.status.StatusService_ClientProxy.updateStatus(Unknown Source)
	at io.quarkus.status.StatusService_ScheduledInvoker_updateStatus_16fdc7fe23b88e46a084c1c3db205f1eac0d1572.invokeBean(Unknown Source)
	at io.quarkus.scheduler.common.runtime.DefaultInvoker.invoke(DefaultInvoker.java:25)
	at io.quarkus.scheduler.common.runtime.DelegateInvoker.invokeDelegate(DelegateInvoker.java:29)
	at io.quarkus.scheduler.common.runtime.StatusEmitterInvoker.invoke(StatusEmitterInvoker.java:35)
	at io.quarkus.scheduler.common.runtime.DelegateInvoker.invokeDelegate(DelegateInvoker.java:29)
	at io.quarkus.scheduler.common.runtime.DelegateInvoker.invokeComplete(DelegateInvoker.java:36)
	at io.quarkus.scheduler.common.runtime.OffloadingInvoker$2.call(OffloadingInvoker.java:54)
	at io.quarkus.scheduler.common.runtime.OffloadingInvoker$2.call(OffloadingInvoker.java:51)
	at io.vertx.core.impl.ContextImpl.lambda$executeBlocking$4(ContextImpl.java:192)
	at io.vertx.core.impl.ContextInternal.dispatch(ContextInternal.java:270)
	at io.vertx.core.impl.ContextImpl$1.execute(ContextImpl.java:221)
	at io.vertx.core.impl.WorkerTask.run(WorkerTask.java:56)
	at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)
	at org.jboss.threads.EnhancedQueueExecutor$Task.doRunWith(EnhancedQueueExecutor.java:2675)
	at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2654)
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1591)
	at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:11)
	at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:11)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:1583)

which is much better than before. Unfortunately, for async calls it doesn't help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants