lambdaclass / lambdaclass/spawned
Cancellation can't interrupt a handler blocked in .await (ctx.stop has no effect on a wedged actor)
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 59
- Forks
- 5
- PR merge metrics
- No merged PRs in 30d
Description
Summary
The actor drain loop evaluates cancellation only between messages — it races the mailbox recv against the cancellation token (tasks/actor.rs). Once a handler is running, ctx.stop() (or dropping the last ActorRef) sets the token, but the loop only checks it after the current handler returns. So an actor whose handler is wedged in an .await (e.g. a network write to a stalled peer) cannot be stopped, and its mailbox is never reclaimed — the canonical way these systems get stuck and leak.
Proposal (either / both)
- Opt-in preemption: race the handler future against the cancellation token (
select(handler, cancelled)) sostop()can abort a wedged handler. Must be opt-in and documented, since aborting mid-.awaitcan leave actor state inconsistent. - Explicit contract + guard: prominently document "handlers must not perform unbounded-time / blocking work; wrap such work in a timeout," and consider a
handle_with_timeouthelper and/or a debug-build warning when a handler runs longer than a configurable threshold.
Why
Today the only workaround is for every handler that awaits I/O to wrap it in tokio::time::timeout so it returns and the between-message cancellation check can fire. A framework-level option (or a loud, discoverable contract) would prevent a common, hard-to-diagnose hang/leak.
Notes
Companion to a separate issue proposing an opt-in bounded mailbox. Motivated by a real production memory leak in a long-running networking service using per-connection actors; reproduction available.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Read the actor drain loop in tasks/actor.rs and use the available reproduction to confirm that cancellation cannot interrupt a handler blocked in .await. Decide whether the scope is opt-in handler preemption, an explicit timeout contract, or both; done requires a documented behavior and appropriate coverage for the chosen approach.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- backend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100