.agents/features/flow-runs.md
Flow Runs records every execution of a flow, tracking its full lifecycle from queuing through completion or failure. It stores compressed execution logs for step-by-step inspection, supports pause-and-resume for delay and webhook-based waits, provides retry strategies for recovering from failures, and emits WebSocket events and application events to notify the frontend and downstream systems in real time.
packages/server/api/src/app/flows/flow-run/ — controller, service, entitypackages/shared/src/lib/automation/flow-run/flow-run.ts — FlowRun typepackages/shared/src/lib/automation/flow-run/dto/ — list, retry, bulk request typespackages/shared/src/lib/automation/flow-run/execution/ — StepOutput, FlowExecution, ExecutionOutputpackages/shared/src/lib/automation/flow-run/log-serializer.ts — zstd compress/decompress helperspackages/web/src/features/flow-runs/api/flow-runs-api.ts — flowRunsApipackages/web/src/features/flow-runs/hooks/flow-run-hooks.ts — flowRunQueries, flowRunMutationspackages/web/src/features/flow-runs/components/runs-table/ — RunsTable, columns.tsx, retry/cancel/archive dialogspackages/web/src/features/flow-runs/components/step-status-icon.tsx — per-step status badgepackages/web/src/app/routes/runs/index.tsx — runs list pagepackages/web/src/app/routes/runs/id/index.tsx — individual run detail pagepackages/web/src/app/builder/run-details/ — step input/output inspector inside the builderpackages/web/src/app/builder/run-list/ — recent runs sidebar in the builderEXECUTION_DATA_RETENTION_DAYS.POST /v1/admin/platforms/runs/retry) is Cloud-only.FlowExecutorContext after execution.waitpoint table representing one paused step on a run. Fields: type (DELAY|WEBHOOK), version (V0|V1 — V1 is the current API), status (PENDING|COMPLETED), stepName, resumeDateTime, responseToSend, resumePayload, workerHandlerId, httpRequestId. Unique on (flow_run_id, step_name).flow_run distinguishing DELAY vs WEBHOOK pauses. Deprecated 2026-04-13 (0.82.0); still read for in-flight V0 runs, scheduled for removal. V1 runs store this information on the waitpoint row instead.parentRunId, created when a flow calls another flow as a step.{ name, type, errorMessage } for the step that caused failure, enabling filtered retries.FlowRun: id, projectId, flowId, flowVersionId, environment (PRODUCTION/TESTING), logsFileId (nullable FK to File), parentRunId (nullable, self-reference for subflows), failParentOnFailure (default true), status, tags[] (nullable), startTime, triggeredBy (nullable FK to User), finishTime, pauseMetadata (JSONB), failedStep (JSONB: name, type, errorMessage), archivedAt (soft delete), stepNameToTest (nullable), stepsCount.
Non-terminal: QUEUED, RUNNING, PAUSED Terminal: SUCCEEDED, FAILED, TIMEOUT, CANCELED, QUOTA_EXCEEDED, MEMORY_LIMIT_EXCEEDED, INTERNAL_ERROR, LOG_SIZE_EXCEEDED
GET / — List runs (cursor pagination, filters: projectId, flowId, status, tags, createdAfter/Before, failedStepName)GET /:id — Get single run with populated dataPOST /:id/retry — Retry single run (strategy: FROM_FAILED_STEP or ON_LATEST_VERSION)POST /retry — Bulk retry with filtersPOST /cancel — Bulk cancel paused/queued runsPOST /archive — Bulk soft delete (set archivedAt)POST /v1/waitpoints — Engine-only: create a waitpoint (PENDING) for a paused stepALL /:id/waitpoints/:waitpointId — Resume a paused run via waitpoint (V1, async)ALL /:id/waitpoints/:waitpointId/sync — Resume and return the flow's response synchronously (V1)ALL /:id/requests/:requestId — V0 legacy resume route (pauseMetadata-based)ALL /:id/requests/:requestId/sync — V0 legacy sync resumectx.run.createWaitpoint({ type, ... }) + ctx.run.waitForWaitpoint(id). Engine POSTs /v1/waitpoints; server inserts a PENDING row keyed on (flow_run_id, step_name).
DELAY waitpoint: server upserts a SystemJobName.RESUME_DELAY_WAITPOINT BullMQ job scheduled at resumeDateTime. When it fires, resumeService.resumeFromWaitpoint enqueues the resume.WEBHOOK waitpoint: resume signal arrives as an HTTP call on /:id/waitpoints/:waitpointId[/sync]. Optional responseToSend is replied immediately to the original webhook trigger.waitpoint-service.complete() takes a pessimistic write lock on the PENDING row. If no row yet, it inserts a COMPLETED row with the resumePayload. When the flow then transitions to PAUSED, flow-runs-queue.ts sees the COMPLETED waitpoint and enqueues the resume immediately. Prevents dropped early callbacks.FlowExecutorContext → re-run the paused step with ExecutionType.RESUME and ctx.resumePayload = waitpoint.resumePayload.AP_PAUSED_FLOW_TIMEOUT_DAYS caps DELAY resumeDateTime; engine throws PausedFlowTimeoutError beyond that.pauseMetadata on flow_run + ctx.run.pause({ pauseMetadata }) + ctx.generateResumeUrl() + /requests/:requestId[/sync] routes. Still functional for in-flight runs; scheduled for removal.refill-paused-jobs migration re-queues legacy paused runs. Waitpoint DELAYs are BullMQ delayed jobs and survive restarts natively.onStart() → emit FLOW_RUN_STARTED application eventonResume() → emit FLOW_RUN_RESUMEDonFinish() → emit FLOW_RUN_FINISHED (terminal states only), notify via WebSocketflowRunsApi.subscribeToTestFlowOrManualRun() uses Socket.IO to start a test run and stream progress updates via WebsocketClientEvent.UPDATE_RUN_PROGRESS. The builder's run-list sidebar polls for recent runs and the run-details panel renders step-by-step input/output from the populated run's execution logs. flowRunMutations.useRetryRun handles the FLOW_RUN_RETRY_OUTSIDE_RETENTION error code with a user-facing toast showing the retention window.