Skip to content

runtime/session: recover and suspend actors after abandoned dispatches - #3635

Open
shashankram wants to merge 1 commit into
kagent-dev:mainfrom
shashankram:suspend-turnless
Open

shashankram wants to merge 1 commit into
kagent-dev:mainfrom
shashankram:suspend-turnless

Conversation

@shashankram

@shashankram shashankram commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

Description

Canceled or timed-out messages can leave an actor RUNNING or RESUMING without an active turn, holding worker capacity. The existing Session lifecycle worker now recovers and suspends these actors while keeping the Session READY for the next message.

  • Persist recovery in runtime_lifecycle_job, with a runtime, operation kind, generation, phase, availability, and owner. Revocation enqueues work atomically; expiry scans discover abandoned dispatches after controller loss. Successful message delivery adds no job writes.
  • Complete interrupted resumes before suspending and recording the durable snapshot, without creating task history. Persisted ownership and suspension intent support restarts and multiple replicas; completion requires the same dispatch and owner.
  • Let newer messages supersede cleanup immediately. Workers stop further runtime calls and retries when superseded, and scans prune obsolete jobs without touching newer work.
  • Yield workers between retries, with backoff capped at 15 seconds. Previously suspended actors without recorded cleanup intent use a persistent observation schedule: one minute initially, then five minutes. Lifecycle counters and structured logs expose progress.
  • Support DB-first upgrades and controller-first rollbacks. Older controllers can clear or replace dispatches without maintaining job metadata; migration rollback preserves Session data.

A resume or suspend already issued to Substrate may finish after a newer message arrives. The message follows normal runtime retry behavior; stale cleanup cannot overwrite its dispatch or snapshot.

Testing

  • PostgreSQL coverage for atomic completion, competing owners, restart takeover, persistent schedules, older-controller writes, and populated upgrade/rollback/re-upgrade.
  • Workflow coverage for supersession, transient failures, worker fairness, crash recovery, and lifecycle telemetry.
  • E2Es for cancellation in RUNNING and RESUMING, verifying the same actor is suspended with a fresh snapshot, released capacity, empty task history, and a successful subsequent message. Updated interrupted-resume deletion coverage.

Change Type

/kind fix

Changelog

Automatically recover and suspend actors left active by canceled or timed-out messages.

@iplay88keys iplay88keys left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 AI-generated review, guided and reviewed by me before posting.

I focused on the migration and on rollbacks within 1.0. I found one rollback issue and have one restart question. Both also apply to #3649. The store and migration tests pass locally at d30cb0b.

@shashankram shashankram changed the title runtime/session: suspend actors after abandoned delivery runtime/session: suspend actors after abandoned dispatches Nov 11, 2026
@shashankram shashankram changed the title runtime/session: suspend actors after abandoned dispatches runtime/session: recover and suspend actors after abandoned dispatches Nov 11, 2026
@shashankram
shashankram force-pushed the suspend-turnless branch 3 times, most recently from 45c96bb to 9dc67e2 Compare November 11, 2026 23:37

@iplay88keys iplay88keys left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM from a migration and rollback perspective. The separate cleanup table is a bit heavy, but the old controller ignores it, so it works here.

@shashankram
shashankram force-pushed the suspend-turnless branch 4 times, most recently from b13c8ce to d1b37c3 Compare November 12, 2026 19:48
\# Description

Canceled or timed-out messages can leave actors running or resuming without
an active turn, retaining worker capacity.

- Use durable runtime lifecycle jobs to recover interrupted resumes and
  suspend actors without turns through the existing worker.
- Preserve ownership and progress across replicas and restarts, with bounded
  retry backoff and persistent scheduling for parked work.
- Let newer messages supersede cleanup without job writes on successful sends.
- Support DB-first upgrades and controller-first rollbacks while preserving
  older-controller writes and recovering abandoned dispatches without jobs.

\# Change Type

```
/kind fix
```

\# Changelog

```release-note
Automatically recover and suspend actors left active by canceled or timed-out messages.
```

\# Additional Notes

Signed-off-by: Shashank Ram <shashank.ram@solo.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants