"Request timeout exceeded" from Apollo Server timeout plugin: do resolvers keep running after abort?
0 reputation · 02 Nov 2020, 00:25 UTC
0 reputation · 02 Nov 2020, 00:25 UTC
I am designing timeout and cancellation handling for a GraphQL HTTP API and need to pin down one behavior before committing to an architecture. When a timeout middleware such as Apollo Server's timeout plugin fires, the client receives a generic Internal Server Error with a message like Request timeout exceeded, but it is unclear what happens to resolver execution that is already in flight.
Some servers expose the underlying request's abort signal (for example via context.signal in GraphQL Yoga), while others require manual extraction, and implementations differ on whether they interrupt resolvers or let them run to completion after the response is abandoned. The GraphQL specification also does not define transactional semantics, so any side effects a resolver performed before the timeout are not automatically rolled back.
Assume a current Apollo Server or Yoga version with a resolver that performs a slow database write followed by a slow read.
Does the timeout plugin actually signal resolvers to stop, or does it only abandon the HTTP response while execution continues? If a client aborts via AbortController before the server timeout, is that propagated to resolvers through the same mechanism? And is there a documented pattern for compensating partial side effects when cancellation lands mid-operation?
34775 reputation · 02 Nov 2020, 02:08 UTC
No. The Apollo Server timeout plugin only aborts the HTTP response; it does not cancel resolver execution. Resolvers that have already started continue to run unless they explicitly observe an abort signal.
req.signal to the GraphQL context.The plugin works as a request‑lifecycle hook that intercepts the final result. When the timer fires it returns a timeout error and stops sending the response, but the resolver execution graph is already in flight and is not torn down, so async work such as a slow DB write followed by a slow read will finish and log completion even though the client received Request timeout exceeded.
requestDidStart plugin hook, set context.signal = req.signal (or the equivalent signal from your HTTP integration).context.signal?.aborted and throw a cancellation error if true. Pass the same signal down to data‑access calls that accept an AbortSignal option.try/finally block that, after the resolver work, checks signal.aborted and runs a compensating action (e.g., delete the written record) when needed.One diagnostic detail that changes the recommendation: which Apollo Server major version and HTTP integration (Express, Fastify, etc.) you are using, because the source of the abort signal (req.signal) differs across integrations. Knowing this determines the safe way to attach the signal to context.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.