Skip to content

Make actor message handling abortable (#4665) - #4665

Open
thedavekwon wants to merge 6 commits into
meta-pytorch:mainfrom
thedavekwon:export-D115847469
Open

Make actor message handling abortable (#4665)#4665
thedavekwon wants to merge 6 commits into
meta-pytorch:mainfrom
thedavekwon:export-D115847469

Conversation

@thedavekwon

@thedavekwon thedavekwon commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Summary:

Make Abort cancel active asynchronous message handling at its next yield. Abort is published through a sticky side channel and has priority whenever cancellation and handler progress are both ready. The standard actor loop observes this channel while idle and while polling work.handle(...); Signal::Abort is removed.

Only user message handling is preemptible. Actor::init, stop and supervision hooks, cleanup, synchronous handler code, and custom ActorInstance loops are not cancelled. After handler cancellation, the existing error path performs child teardown, cleanup, supervision reporting, introspection shutdown, and terminal status publication.

Proc timeout escalation marks an already proc-owned root actor Zombie before publishing Abort. Forced parent teardown detaches each residual direct child, promotes it to proc ownership, marks it Zombie, and publishes Abort, allowing ancestor teardown to continue.

Design invariant: once the standard actor loop observes Abort, it drops any in-flight asynchronous handler and starts no subsequent handler. Abort never bypasses lifecycle teardown; Zombie remains nonterminal until the actor publishes its true terminal status.

Differential Revision: D115847469

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Aug 13, 2026
@meta-codesync

meta-codesync Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

@thedavekwon has exported this pull request. If you are a Meta employee, you can view the originating Diff in D115847469.

@meta-codesync meta-codesync Bot changed the title Preserve runtime finalization during actor abort Make actor message handling abortable Sep 1, 2026
Summary:
Pull Request resolved: meta-pytorch#4646

Use terminal `ActorSupervisionEvent`s for successful, failed, and zombie child completion, and remove the parallel `Signal::ChildStopped` path.

Each child enqueues exactly one terminal event while retaining its direct-parent ownership edge. The event carries private, non-serialized `child_to_unlink` metadata for that hop; the parent removes the edge when it consumes the event, before invoking the actor supervision handler. `actor_id` continues to identify the original event subject when failures propagate through multiple levels.

The parent child map is therefore a barrier for unconsumed completion events. This prevents teardown from consuming the final event before observing the corresponding unlink while preserving event delivery before terminal status becomes externally visible. Custom actor loops consume the same terminal events.

Differential Revision: D114913598
Summary:
Pull Request resolved: meta-pytorch#4664

Replace the separate Kill and Abort vocabulary with one forced actor operation: Abort. Make `abort()` the primary API and retain `kill()` only as a compatibility alias.

Design invariant: every forced actor termination has one control signal, one terminal cause, and one result: `Abort` and `Aborted`. Callers and supervision no longer distinguish semantically identical forced-stop paths.

Update internal producers, consumers, status reporting, documentation, and tests to use the unified outcome without changing cancellation behavior.

Differential Revision: D115847493
Summary:
Move cooperative shutdown out of the runtime teardown path and into `Actor::handle_stop`, while keeping the actor loop available until the actor requests exit.

Design invariant: the runtime delivers `Stop` and `DrainAndStop`, but the actor owns how cooperative shutdown completes. `Stop` invokes the hook immediately; `DrainAndStop` closes handler ingress and queues the hook behind already accepted work. The default hook closes ingress, preserves the requested mode and reason, forwards that request to current direct children, and exits only after every direct child completes. Overrides may return and complete asynchronously through ordinary messages or supervision events.

A direct child remains in the parent ownership map until the parent consumes its terminal supervision event. On receipt, the runtime removes the exact direct-child edge and invokes `handle_child_stopped` before `handle_supervision_event`. The child map is therefore the completion barrier during cooperative shutdown, and child failures remain observable before the parent completes. `ActorSupervisionEvent.actor_id` remains the propagated event subject; private, non-serialized `child_to_unlink` records only the hop-local ownership edge.

Remote actors remain represented by local `Supervisor` proxies rather than being inserted into the local ownership topology. A proxy forwards stop requests before or after `Linked` and remains alive until remote terminal, unlink, or liveness handling resolves its local lifecycle.

Once an actor loop returns, any child still linked is residual. The following diff transfers those children to proc ownership and aborts them; later diffs make active user hooks Abort-aware.

Differential Revision: D110433174
Summary:
After an actor loop exits, detach every remaining direct child, promote it to a proc root, mark it `Zombie`, and request Abort without traversing descendants or waiting for completion.

Design invariant: every live actor has exactly one current owner: one live parent or the proc root index. The child parent-link lock serializes completion routing with forced detachment. While the parent loop is active, a terminal event retains the parent link until that event is consumed. Once the parent loop exits, any still-linked child is residual and teardown transfers it to proc ownership. If detachment wins before completion routes, the later terminal event remains available to introspection but does not re-enter supervision.

Each actor handles only its own direct residual children. Proc teardown remains root-oriented, remote descendants use liveness orphan handling, and no stuck descendant can pin an ancestor teardown.

Differential Revision: D114913597
Summary:
Remove the per-actor cleanup deadline and its Rust, Python, documentation, and test configuration surface. Transport flush timeouts remain unchanged.

Design invariant: cleanup is ordinary user code, not a separate teardown phase with its own runtime timeout policy. Graceful and failure exits await cleanup normally; the following Abort-aware lifecycle diff is solely responsible for skipping or preempting cleanup during forced termination.

This leaves deadline and escalation policy with explicit teardown callers and avoids competing cleanup, actor, and proc timers.

Reviewed By: mariusae

Differential Revision: D110433730
thedavekwon added a commit to thedavekwon/monarch that referenced this pull request Sep 2, 2026
Summary:
Pull Request resolved: meta-pytorch#4665

Make `Abort` cancel active asynchronous message handling at its next yield. Abort is published through a sticky side channel and has priority whenever cancellation and handler progress are both ready. The standard actor loop observes this channel while idle and while polling `work.handle(...)`; `Signal::Abort` is removed.

Only user message handling is preemptible. `Actor::init`, stop and supervision hooks, cleanup, synchronous handler code, and custom `ActorInstance` loops are not cancelled. After handler cancellation, the existing error path performs child teardown, cleanup, supervision reporting, introspection shutdown, and terminal status publication.

Proc timeout escalation marks an already proc-owned root actor `Zombie` before publishing Abort. Forced parent teardown detaches each residual direct child, promotes it to proc ownership, marks it `Zombie`, and publishes Abort, allowing ancestor teardown to continue.

Design invariant: once the standard actor loop observes Abort, it drops any in-flight asynchronous handler and starts no subsequent handler. Abort never bypasses lifecycle teardown; `Zombie` remains nonterminal until the actor publishes its true terminal status.

Differential Revision: D115847469
@meta-codesync meta-codesync Bot changed the title Make actor message handling abortable Make actor message handling abortable (#4665) Sep 2, 2026
thedavekwon added a commit to thedavekwon/monarch that referenced this pull request Sep 2, 2026
Summary:
Pull Request resolved: meta-pytorch#4665

Make `Abort` cancel active asynchronous message handling at its next yield. Abort is published through a sticky side channel and has priority whenever cancellation and handler progress are both ready. The standard actor loop observes this channel while idle and while polling `work.handle(...)`; `Signal::Abort` is removed.

Only user message handling is preemptible. `Actor::init`, stop and supervision hooks, cleanup, synchronous handler code, and custom `ActorInstance` loops are not cancelled. After handler cancellation, the existing error path performs child teardown, cleanup, supervision reporting, introspection shutdown, and terminal status publication.

Proc timeout escalation marks an already proc-owned root actor `Zombie` before publishing Abort. Forced parent teardown detaches each residual direct child, promotes it to proc ownership, marks it `Zombie`, and publishes Abort, allowing ancestor teardown to continue.

Design invariant: once the standard actor loop observes Abort, it drops any in-flight asynchronous handler and starts no subsequent handler. Abort never bypasses lifecycle teardown; `Zombie` remains nonterminal until the actor publishes its true terminal status.

Differential Revision: D115847469
Summary:
Pull Request resolved: meta-pytorch#4665

Make `Abort` cancel active asynchronous message handling at its next yield. Abort is published through a sticky side channel and has priority whenever cancellation and handler progress are both ready. The standard actor loop observes this channel while idle and while polling `work.handle(...)`; `Signal::Abort` is removed.

Only user message handling is preemptible. `Actor::init`, stop and supervision hooks, cleanup, synchronous handler code, and custom `ActorInstance` loops are not cancelled. After handler cancellation, the existing error path performs child teardown, cleanup, supervision reporting, introspection shutdown, and terminal status publication.

Proc timeout escalation marks an already proc-owned root actor `Zombie` before publishing Abort. Forced parent teardown detaches each residual direct child, promotes it to proc ownership, marks it `Zombie`, and publishes Abort, allowing ancestor teardown to continue.

Design invariant: once the standard actor loop observes Abort, it drops any in-flight asynchronous handler and starts no subsequent handler. Abort never bypasses lifecycle teardown; `Zombie` remains nonterminal until the actor publishes its true terminal status.

Differential Revision: D115847469
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot. meta-exported

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant