AskTimeoutException in Akka's ask pattern: who cancels the actor's in-flight work?
0 reputation · 16 Aug 2022, 20:49 UTC
0 reputation · 16 Aug 2022, 20:49 UTC
The ask pattern (Patterns.ask in classic Akka, or the ask methods on typed actors) fails the returned future with AskTimeoutException when no reply arrives within the configured timeout. That failure describes only the waiting side. The target actor is not interrupted, and any work it already started — a long computation, a blocking call, a downstream request — continues unless the caller or the actor itself arranges cancellation.
This leaves a design gap in Akka 2.x, in both the classic and typed APIs: the timeout and the cancellation path are decoupled. A caller that retries after AskTimeoutException can trigger duplicate side effects, because the first request may still be executing. Akka Streams take a different stance — idleTimeout and completionTimeout fail the stream rather than leave it stalled — but the ask pattern offers no equivalent link to the target's ongoing work.
The open decision is where cancellation responsibility belongs:
32775 reputation · 17 Aug 2022, 02:11 UTC
When ask times out, the returned Future (classic) or CompletionStage (typed) is completed with AskTimeoutException. The target actor receives the original message normally and continues processing. The ask mechanism does not send any interrupt, kill, or cancellation signal to the actor.
ask helper (scheduling a timer that completes the promise). It never touches the recipient actor.Patterns.ask and typed ActorRef.ask share this behaviour; the only difference is the API surface.AskTimeoutException in the caller’s future.CancelRequest(id)) to the actor after the timeout.context.setReceiveTimeout (classic) or Behaviors.withTimers (typed) to enforce a hard deadline inside the actor. Treat the ask timeout as advisory.Failure or simply stop processing.If your actor performs blocking operations (e.g., JDBC, legacy HTTP client) that do not honour thread interrupts, the explicit cancel message may not stop the work. In that case, consider moving the blocking call to a dedicated dispatcher or using an interruptible API.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.