Skip to content

perf(workflow): engine overhead dominates a long uncapped for_each #1162

Closed

Description

@SaulMoro

Problem

A for_each over 1,000 items with no max_parallel takes about 42 s with --driver local, even when each item only runs true. The commands take almost none of that time: the engine takes nearly all of it.

Shape (real CLI, --driver local) Whole run
uncapped, 1,000 items 42 s
max_parallel: 8, 200 items 3.5 s

Where the time goes

each next / report              about 2 calls per item
  read run file                 parses the whole file through the schema
  reconcile                     settles every running item's workflow
  write run file                writes the whole file

Every call pays both costs, and both grow with the run. Once the settling work is cut, parsing the file is about a third of the run.

Options

Option Gain Catch
Validate the run file more cheaply on read, for example without the per-step schema pass up to about a third that read is what guards against a corrupt or hand-edited file
Persist what is left to reconcile, and settle only those scopes the settling cost an edited file must still fall back to a full reconcile

Tried and dropped in #1148: an in-memory incremental reconcile. It was correct, but it only took the run from 41 s to 33 s, and only when one process drives the whole run.

Done when

A 1,000-item uncapped run spends most of its time in its commands, measured with the real CLI.

Follow-up to #1079 and #1148.

Activity

  1. SaulMoro commented on Oct 20, 2026

    @SaulMoro
    CollaboratorAuthor

    #1175 adds work to report that grows with the run. On each successful report that carries changes, branchStillUsed plans the branch of every unsettled step (engine.ts:1141-1149), and each plan runs planWorkspace, which scans run.steps several times (ancestorsOf, itemsOf, itemsAfter). In an uncapped for_each with workspace: new, that is O(N²) per report. I have read this from the code, not measured it. A 1,000-item workspace: new run spends most of its time on git worktree add and commits, so I'd add it to the measurements with engine time per report kept apart from git and tool time, and check that it stays flat from 100 to 1,000 items. A branch-to-unsettled-users index in the persisted reconcile state is one fix, if the measurement calls for it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions