Repository navigation
feat(workflow-executor): run steps once per record of a Multiple related-records step #2026
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
4f13a00
c3a2396
6474717
f737911
005e522
95a4132
e925249
032648a
9908084
eb4e199
67d25ef
e29023f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| --- | ||
| status: accepted | ||
| date: 2026-10-21 | ||
| tags: [workflow-executor, run-lock, multiple-related-records] | ||
| affected_components: [workflow-executor] | ||
| --- | ||
|
|
||
| # A step running once per record renews its run lock with the orchestrator before each record | ||
|
|
||
| A step running once per record can outlast the orchestrator's 7-minute run lock, and an operator's abort must stop it before its next record. So before each record the runtime calls `POST /api/workflow-orchestrator/renew-run-lock` on forestadmin-server with the lock it holds: a 409 (the run was aborted or its lock lost) stops the step without reporting, and an orchestrator that cannot answer leaves the step running under the lock it already holds. Accepted cost: released runtimes call this route, so the orchestrator must keep serving it, and a run whose renewals go unanswered for 7 minutes can still be claimed by another runtime. Rejected: handing the run back and claiming it again about once a minute, which needs no route but lets an abort wait up to a minute while more records run, and one record per dispatch, the simplest loop but up to 30 seconds between records, 25 minutes for 50. |
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,8 +24,18 @@ function toExecutionStatus(outcome: StepOutcome): ServerExecutionStatus { | |
| export default function toUpdateStepRequest( | ||
| runId: string, | ||
| outcome: StepOutcome, | ||
| options?: { clearsError?: boolean }, | ||
| ): ServerUpdateStepRequest { | ||
| const context: Record<string, unknown> = { status: outcome.status }; | ||
|
|
||
| // The orchestrator merges each report into the context the error left, and keeps a null where | ||
| // it drops an undefined key, so only a null clears it. | ||
| if (options?.clearsError && outcome.status !== 'error') { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Claude Opus 5.5 (claude-opus-5-5): Should fix: a retried step that fails again keeps the old error's kind and source step, so the run view shows stale copy. Code
A way out: drop the Reproduction
|
||
| context.error = null; | ||
| context.errorKind = null; | ||
| context.errorSourceStepIndex = null; | ||
| } | ||
|
|
||
| if (outcome.error !== undefined) context.error = outcome.error; | ||
| if (outcome.errorKind !== undefined) context.errorKind = outcome.errorKind; | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.