Bound Agent Workflow tracking so that local state is automatically pruned - #1935
Bound Agent Workflow tracking so that local state is automatically pruned#1935ericclemmons wants to merge 7 commits into
Conversation
🦋 Changeset detectedLatest commit: ebc399c The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
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 |
agents
@cloudflare/ai-chat
@cloudflare/codemode
hono-agents
@cloudflare/shell
@cloudflare/think
@cloudflare/voice
@cloudflare/worker-bundler
commit: |
|
/bonk review |
|
UnknownError: ProviderInitError |
|
@ericclemmons Bonk workflow failed. Check the logs for details. View workflow run · To retry, trigger Bonk again. |
430722e to
cd9cf26
Compare
cedeedc to
05181d6
Compare
cd9cf26 to
7a6d226
Compare
05181d6 to
4884a81
Compare
7a6d226 to
b48a179
Compare
45eeb85 to
6ea30dd
Compare
b48a179 to
ba7dcb6
Compare
ba7dcb6 to
0eb5018
Compare
|
/bonk review this plz |
| completed_at = ${completedAt} | ||
| completed_at = ${completedAt}, | ||
| expires_at = ${expiresAt} | ||
| WHERE workflow_id = ${workflowId} |
There was a problem hiding this comment.
_updateWorkflowTracking unconditionally overwrites completed_at and expires_at for every status:
const completedAt = completedStatuses.includes(statusName) ? now : null;
const expiresAt = completedAt ? ... : null;
// ...
SET completed_at = ${completedAt}, expires_at = ${expiresAt}If reconciliation polls a still-running instance (status: "running"), the UPDATE blankets completed_at = NULL, expires_at = NULL over whatever was there. This is fine for genuinely non-terminal rows, but if a race delivers a terminal callback between the workflow.get() call in _cleanupWorkflowTracking and this UPDATE, the already-persisted expiry is silently erased and the row reverts to unbounded — the exact state the PR aims to eliminate.
Consider a WHERE guard like the one onWorkflowCallback already uses (AND status NOT IN ('terminated', 'paused')), or at minimum skip writing completed_at/expires_at when the new status is non-terminal and the existing row is already terminal.
| this.sql` | ||
| DELETE FROM cf_agents_workflows | ||
| WHERE expires_at IS NOT NULL AND expires_at <= ${now} | ||
| `; |
There was a problem hiding this comment.
The expired-row deletion at L6056-6059 already runs before reconciliation. This second identical DELETE at the bottom of the method is redundant — reconciliation calls _updateWorkflowTracking which sets expires_at but never sets it into the past, so no new expired rows can appear between the two DELETE passes in the same invocation.
|
The review was submitted with 2 inline comments. Here is the summary: Submitted 2 inline findings on the PR. Summary of additional observations that didn't warrant inline comments: Overall assessment: The design is sound — deriving Minor notes not posted inline (non-blocking):
|
tl;dr – Automatically prune terminal Agent Workflow tracking rows from local SQLite.
Agent Workflow tracking currently grows without bound even after the Workflow platform expires instance state. This persists normalized success/error retention, derives an indexed
expires_atafter the terminal outcome is known, and maintains one earliest-expiry cleanup alarm per Agent or facet owner.Cleanup is armed when
runWorkflow()first writes tracking state, reconciles missed terminal callbacks after eviction or crashes, deletes expired local rows, and stops when no cleanup remains. Omitted retention uses a bounded 30-day local fallback because the SDK cannot detect Workers Free versus Paid; this improves the existing unbounded behavior.This deletes only Agent-local SQLite tracking. It never deletes Workflow platform instances, state, or logs.
References: retention passthrough PR, Agents cleanup strategy