lambdaclass / lambdaclass/spawned

Cancellation can't interrupt a handler blocked in .await (ctx.stop has no effect on a wedged actor)

Open
#171 0 comments 0 reactions 0 assignees View on GitHub

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)) so stop() can abort a wedged handler. Must be opt-in and documented, since aborting mid-.await can 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_timeout helper 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

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.