Skip to content

fix(agent-invocations): End stranded agent invocations from the heartbeat - #2640

Open
sentry-junior[bot] wants to merge 2 commits into
mainfrom
fix/stranded-agent-invocations
Open

sentry-junior[bot] wants to merge 2 commits into
mainfrom
fix/stranded-agent-invocations

Conversation

@sentry-junior

@sentry-junior sentry-junior Bot commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #2627. An independent review of #2627 found that it still left agent invocations open on other stop paths.

Problem

  • fix(agent-invocations): Tell the parent when a child's work stops after its tries run out #2627 ends a child's open agent invocations from a hook inside the heartbeat's lease-expiry stop. Two other paths also stop work and drop the mailbox, and neither runs the hook:
    • recordConversationRetry, when an error escapes the worker's last try.
    • recordAttemptFailure, when it dead-letters messages.
      On those paths, the agent invocations stay open and the parent never gets a result.
  • The hook fails agent invocations before the stop is written. If the 10s mutation lock expires or the heartbeat dies before that write, the work can start again, even though its agent invocations already failed.

Change

  • Remove the hook. task-execution goes back to its shape before fix(agent-invocations): Tell the parent when a child's work stops after its tries run out #2627.
  • Add a heartbeat phase, recoverStrandedAgentInvocations. It ends an open, appended agent invocation only when all of these are true:
    • its input left the child mailbox,
    • the child has no lease,
    • the child's status is failed or idle.
      Consumed ids stay in inboundMessageIds, so that input can never be appended again. Because the state cannot run again, the phase needs no lock, and it covers every stop path.
  • The phase runs after mailbox-append recovery and before result recovery. The parent gets the result in the same heartbeat.

Tests
agent-invocation-worker-crash.test.ts:

  • The killed-worker case still passes. It now also checks that the agent invocation stays running after each try except the last.
  • New case: an error escapes the worker's last try (recordConversationRetry stop) while a follow-up waits in the mailbox. Both agent invocations fail, and the parent gets 2 results. This case fails on main.

Checks

  • tsc, lint, test-architecture and file-length pass.
  • The agent-invocation, agent-dispatch, task-execution and heartbeat suites pass, except for local timeouts that also happen on main (durable-queue 4, agent-dispatch-work 1).

via @dcramer.

--

View Session [Sentry]

…beat

#2627 ended a child's open agent invocations from a hook inside the
heartbeat's lease-expiry stop. Two other stop paths drop the mailbox
without it: recordConversationRetry when an error escapes the worker's
last try, and recordAttemptFailure when it dead-letters messages. Their
agent invocations stay open, and the parent never gets a result. The
hook also failed agent invocations before the stop was written, so a
lost lock or a dead heartbeat could fail work that still ran.

Replace the hook with a heartbeat phase. It ends an open, appended agent
invocation only when its input left the child mailbox and the child has
no lease and no work to resume. That state cannot run again, so the
phase needs no lock and covers every stop path. task-execution is back
to its shape before #2627.

Co-Authored-By: David Cramer <23610+dcramer@users.noreply.github.com>
@vercel

vercel Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
junior-docs Ready Ready Preview Nov 4, 2026 12:37am UTC

Request Review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 89b3208. Configure here.

…n every open agent invocation

A pending agent invocation whose input left the mailbox with no lease can
never start, so end it even when the child has new work. Page through every
open agent invocation, so long-lived healthy ones cannot hide stranded ones.
@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

130 screenshot changes — 0 changed · 130 added · 0 removed

Review screenshots in Frameshift

@sentry-junior

sentry-junior Bot commented Nov 4, 2026

Copy link
Copy Markdown
Contributor Author

check / types and test / junior unit failed here because of a break on main, not this PR: web-batch-messages.test.ts imported webActorFromEmail, which #2630 removed (TS2305). #2643 fixed it on main as e35103a2d. Rebase onto main to clear those checks. ci / required failed only because those two did.

This branch was successfully deployed

1 active deployment
Preview – junior-docs — dc6df188 Deployed Nov 4, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk: medium PR risk score: medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant