Skip to content

feat(agents): synchronous Lifecycle job push and cancel - #2420

Closed
mattzcarey wants to merge 1 commit into
mainfrom
feat/lifecycle-jobs-sync
Closed

mattzcarey wants to merge 1 commit into
mainfrom
feat/lifecycle-jobs-sync

Conversation

@mattzcarey

@mattzcarey mattzcarey commented Sep 30, 2026 •

Copy link
Copy Markdown
Member

Lifecycle capabilities can now push or cancel a job in the same transactionSync as their own rows, so the job and the rows commit or roll back together.

this.lifecycle.storage.transactionSync(() => {
  store.enqueue(scope, id, input); // the capability's row
  this.lifecycle.jobs.pushSync({ id: jobId, fn: "step", time: Date.now() });
});
await this.lifecycle.jobs.rearm(); // sync mutations skip the re-arm
  • jobs.pushSync(options) / jobs.cancelSync(id): same semantics as push / cancel, but synchronous, and they don't re-arm the physical alarm. Call rearm() after the commit.
  • JobQueue recreates cf_agents_jobs when a rolled-back transaction also rolled back its CREATE TABLE (the cached "table exists" flag goes stale otherwise).
  • Docs: docs/agents/lifecycle.md.

Why: a driver that queues a row and its wake job with the async push has a window where the row exists without a job, or the job without the row. Taken from the driver in #2396. The pi harness example (#2419) is stacked on this.


Devin Review

jobs.pushSync() and jobs.cancelSync() write the job inside the caller's
storage.transactionSync, so it commits or rolls back with the capability's
own rows. They skip the re-arm; call jobs.rearm() after the commit. The
queue also recreates its table when a rolled-back transaction took the
CREATE TABLE with it.
@changeset-bot

changeset-bot Bot commented Sep 30, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 08712c2

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
agents Patch
@cloudflare/agent-think Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@devin-ai-integration devin-ai-integration Bot 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.

Devin Review found 1 potential issue.

Devin Review

Comment thread docs/agents/lifecycle.md
Comment on lines 193 to +205
The queue is ordered by timestamp, and every queue mutation re-arms the
physical alarm automatically — there is no explicit rearm call. When the
physical alarm automatically. The one exception is a job that must commit with
the capability's own rows. `jobs.pushSync()` and `jobs.cancelSync()` write
synchronously inside a `storage.transactionSync`, so the job and the rows
commit or roll back together. They skip the re-arm, so call `jobs.rearm()`
once the transaction commits:

```ts
this.lifecycle.storage.transactionSync(() => {
this.#insertRow(id, input);
this.lifecycle.jobs.pushSync({ id, fn: "step", time: Date.now() });
});
await this.lifecycle.jobs.rearm();

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.

🔍 Check upstream Lifecycle documentation sync

The documentation rules require a matching update in cloudflare-docs. That repository is outside this PR, so confirm the new synchronous job guidance is ported.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

@agent-think

agent-think Bot commented Sep 30, 2026

Copy link
Copy Markdown
Contributor

✅ agents import sizes: no significant changes (040458ed → 08712c23, workflow run)

mattzcarey added a commit to mattzcarey/agents that referenced this pull request Sep 30, 2026
submit() admits into pi once, after the session's wake has a job. The
wake's step waits while pi has live tasks in the session and parks when
it has none, so it never admits or replays. The copied driver writes its
row and job atomically with jobs.pushSync (cloudflare#2420).
@pkg-pr-new

pkg-pr-new Bot commented Sep 30, 2026

Copy link
Copy Markdown

Open in StackBlitz

agents

npm i https://pkg.pr.new/agents@2420

@cloudflare/ai-chat

npm i https://pkg.pr.new/@cloudflare/ai-chat@2420

@cloudflare/codemode

npm i https://pkg.pr.new/@cloudflare/codemode@2420

hono-agents

npm i https://pkg.pr.new/hono-agents@2420

@cloudflare/shell

npm i https://pkg.pr.new/@cloudflare/shell@2420

@cloudflare/think

npm i https://pkg.pr.new/@cloudflare/think@2420

@cloudflare/voice

npm i https://pkg.pr.new/@cloudflare/voice@2420

@cloudflare/worker-bundler

npm i https://pkg.pr.new/@cloudflare/worker-bundler@2420

commit: 08712c2

mattzcarey added a commit to mattzcarey/agents that referenced this pull request Sep 30, 2026
submit() admits into pi once, after the session's wake has a job. The
wake's step waits while pi has live tasks in the session and parks when
it has none, so it never admits or replays. The copied driver writes its
row and job atomically with jobs.pushSync (cloudflare#2420).
@mattzcarey

Copy link
Copy Markdown
Member Author

Not needed: the pi harness example (#2419) now wakes with a plain per-session Lifecycle job, so nothing needs an atomic row-plus-job push.

@mattzcarey mattzcarey closed this Oct 1, 2026
@mattzcarey
mattzcarey deleted the feat/lifecycle-jobs-sync branch October 1, 2026 09:06
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