@cascade-flow/worker 0.2.4 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -74,6 +74,13 @@ await worker.start();
74
74
  - **Step timeout** → `StepFailed` event → Retry with delay (if configured)
75
75
  - **Terminal failure** → Scheduler stops scheduling → `WorkflowFailed`
76
76
 
77
+ ## Checkpoints
78
+
79
+ Workers track checkpoint progress within steps via `StepCheckpoint` and `StepCheckpointFailed` events. This enables:
80
+ - Fine-grained progress tracking for long-running steps
81
+ - Replay of completed checkpoints on retry (skip already-done work)
82
+ - Pinpoint error locations when failures occur mid-step
83
+
77
84
  ## API
78
85
 
79
86
  ```typescript
@@ -3,11 +3,43 @@ import { type LoadedStep } from "@cascade-flow/runner";
3
3
  /**
4
4
  * Check if all dependencies for a step are satisfied
5
5
  * Returns true if the step can be scheduled
6
+ *
7
+ * IMPORTANT: Both required AND optional dependencies must reach a terminal state
8
+ * (completed or skipped) before a step can be scheduled. The distinction between
9
+ * required and optional only affects CASCADE SKIP behavior:
10
+ *
11
+ * - Required dependency skips → dependent step is cascade skipped
12
+ * - Optional dependency skips → dependent step executes with undefined value
13
+ *
14
+ * This means optional dependencies still BLOCK scheduling until they either complete
15
+ * or skip. They only differ in how the dependent step handles the skipped state.
16
+ *
17
+ * @param step - The step to check dependencies for
18
+ * @param backend - Backend interface for loading events
19
+ * @param workflowSlug - Workflow identifier
20
+ * @param runId - Run identifier
21
+ * @returns true if all dependencies are in terminal state and satisfy execution requirements
6
22
  */
7
23
  export declare function checkDependenciesSatisfied(step: LoadedStep, backend: Backend, workflowSlug: string, runId: string): Promise<boolean>;
8
24
  /**
9
25
  * Load outputs from all dependencies
10
26
  * Returns a map of dependency alias to output value
27
+ *
28
+ * This function should only be called after checkDependenciesSatisfied returns true,
29
+ * ensuring all dependencies are in terminal state.
30
+ *
31
+ * Behavior by dependency state:
32
+ * - Completed: Returns parsed JSON output
33
+ * - Skipped + Optional: Returns undefined
34
+ * - Skipped + Required: Throws error (should never happen - step should be cascade skipped)
35
+ * - Any other state: Throws error (should never happen - checkDependenciesSatisfied should prevent scheduling)
36
+ *
37
+ * @param step - The step to load dependency outputs for
38
+ * @param backend - Backend interface for loading events
39
+ * @param workflowSlug - Workflow identifier
40
+ * @param runId - Run identifier
41
+ * @returns Map of dependency alias to output value (undefined for skipped optional deps)
42
+ * @throws Error if dependency is not in a valid terminal state
11
43
  */
12
44
  export declare function loadDependencyOutputs(step: LoadedStep, backend: Backend, workflowSlug: string, runId: string): Promise<Record<string, any>>;
13
45
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"dependency-resolver.d.ts","sourceRoot":"","sources":["../../src/execution/dependency-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iCAAiC,CAAC;AAE/D,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAIvD;;;GAGG;AACH,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,OAAO,EAChB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,OAAO,CAAC,CA+BlB;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,OAAO,EAChB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAoC9B;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,UAAU,EAAE,EACtB,YAAY,GAAE,OAAe,GAC5B,UAAU,EAAE,CAed"}
1
+ {"version":3,"file":"dependency-resolver.d.ts","sourceRoot":"","sources":["../../src/execution/dependency-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iCAAiC,CAAC;AAE/D,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAGvD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,OAAO,EAChB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,OAAO,CAAC,CAkClB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,OAAO,EAChB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CA0C9B;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,UAAU,EAAE,EACtB,YAAY,GAAE,OAAe,GAC5B,UAAU,EAAE,CAed"}
package/dist/index.js CHANGED
@@ -16,20 +16,21 @@ async function checkDependenciesSatisfied(step, backend, workflowSlug, runId) {
16
16
  stepId: dep.id
17
17
  });
18
18
  if (depEvents.length === 0) {
19
- const isOptionalDep2 = isOptional(step.dependencies[depKey]);
20
- if (!isOptionalDep2) {
21
- return false;
22
- }
23
- continue;
19
+ return false;
24
20
  }
25
21
  const depState = projectStepState(depEvents, workflowSlug);
26
22
  const isOptionalDep = isOptional(step.dependencies[depKey]);
27
- if (depState.status === "skipped" && isOptionalDep) {
23
+ if (depState.status === "completed") {
28
24
  continue;
29
25
  }
30
- if (depState.status !== "completed") {
31
- return false;
26
+ if (depState.status === "skipped") {
27
+ if (isOptionalDep) {
28
+ continue;
29
+ } else {
30
+ return false;
31
+ }
32
32
  }
33
+ return false;
33
34
  }
34
35
  return true;
35
36
  }
@@ -41,12 +42,7 @@ async function loadDependencyOutputs(step, backend, workflowSlug, runId) {
41
42
  stepId: depStep.id
42
43
  });
43
44
  if (depEvents.length === 0) {
44
- const isOptionalDep2 = isOptional(step.dependencies[depKey]);
45
- if (!isOptionalDep2) {
46
- throw new Error(`Required dependency ${depStep.name} has no events`);
47
- }
48
- dependencyOutputs[depKey] = undefined;
49
- continue;
45
+ throw new Error(`Dependency ${depStep.name} has no events - step was scheduled prematurely`);
50
46
  }
51
47
  const depState = projectStepState(depEvents, workflowSlug);
52
48
  const isOptionalDep = isOptional(step.dependencies[depKey]);
@@ -54,8 +50,11 @@ async function loadDependencyOutputs(step, backend, workflowSlug, runId) {
54
50
  dependencyOutputs[depKey] = undefined;
55
51
  continue;
56
52
  }
57
- if (depState.status !== "completed" || !depState.output) {
58
- throw new Error(`Dependency ${depStep.name} is not completed`);
53
+ if (depState.status !== "completed") {
54
+ throw new Error(`Dependency '${depStep.name}' is not ready (status: ${depState.status}). ` + `This should not happen - checkDependenciesSatisfied should have prevented scheduling.`);
55
+ }
56
+ if (!depState.output) {
57
+ throw new Error(`Dependency '${depStep.name}' has no output despite being completed`);
59
58
  }
60
59
  dependencyOutputs[depKey] = JSON.parse(depState.output);
61
60
  }
@@ -563,11 +562,9 @@ class StepWorker {
563
562
  let allStepsCompleted = true;
564
563
  let anyStepFailed = false;
565
564
  let failedStepName;
565
+ const allStepEvents = await this.backend.loadStepEventsForProjection(workflowSlug, runId);
566
566
  for (const step of workflowData.steps) {
567
- const stepEvents = await this.backend.loadEvents(workflowSlug, runId, {
568
- category: "step",
569
- stepId: step.id
570
- });
567
+ const stepEvents = allStepEvents.get(step.id) || [];
571
568
  if (stepEvents.length === 0) {
572
569
  allStepsCompleted = false;
573
570
  const canSchedule = await checkDependenciesSatisfied(step, this.backend, workflowSlug, runId);
@@ -627,6 +624,26 @@ class StepWorker {
627
624
  }
628
625
  }
629
626
  }
627
+ async loadCheckpointsFromEvents(workflowSlug, runId, stepId) {
628
+ const events = await this.backend.loadEvents(workflowSlug, runId, {
629
+ category: "step",
630
+ stepId
631
+ });
632
+ const checkpoints = new Map;
633
+ for (const event of events) {
634
+ if (event.type === "StepCheckpoint") {
635
+ if (!checkpoints.has(event.name)) {
636
+ checkpoints.set(event.name, []);
637
+ }
638
+ const arr = checkpoints.get(event.name);
639
+ while (arr.length <= event.sequenceNumber) {
640
+ arr.push("");
641
+ }
642
+ arr[event.sequenceNumber] = event.data;
643
+ }
644
+ }
645
+ return checkpoints;
646
+ }
630
647
  async executeStep(workflowSlug, runId, stepId) {
631
648
  const stepKey = createStepKey(workflowSlug, runId, stepId);
632
649
  let startTime = getMicrosecondTimestamp5();
@@ -699,6 +716,7 @@ class StepWorker {
699
716
  const stepFile = join(step.dir, "step.ts");
700
717
  const submissionTimeoutMs = runSubmittedEvent && runSubmittedEvent.timeoutUs ? Math.floor(runSubmittedEvent.timeoutUs / 1000) : undefined;
701
718
  const timeout = step.timeoutMs ?? submissionTimeoutMs ?? 300000;
719
+ const existingCheckpoints = await this.loadCheckpointsFromEvents(workflowSlug, runId, stepId);
702
720
  const abortController = new AbortController;
703
721
  const executionPromise = executeStepInProcess(stepFile, step.id, dependencyOutputs, ctx, attemptNumber, this.backend, async (log) => {
704
722
  const logEvent = {
@@ -713,7 +731,21 @@ class StepWorker {
713
731
  timestampUs: log.timestamp
714
732
  };
715
733
  await this.backend.appendEvent(workflowSlug, runId, logEvent);
716
- }, {
734
+ }, async (checkpoint) => {
735
+ await this.backend.saveStepCheckpoint(workflowSlug, runId, stepId, {
736
+ name: checkpoint.name,
737
+ sequenceNumber: checkpoint.sequenceNumber,
738
+ attemptNumber,
739
+ data: checkpoint.data
740
+ });
741
+ }, async (failure) => {
742
+ await this.backend.saveStepCheckpointFailed(workflowSlug, runId, stepId, {
743
+ name: failure.name,
744
+ sequenceNumber: failure.sequenceNumber,
745
+ attemptNumber,
746
+ error: JSON.parse(failure.error)
747
+ });
748
+ }, existingCheckpoints, {
717
749
  signal: abortController.signal
718
750
  });
719
751
  const timeoutTimer = setTimeout(() => {
@@ -838,4 +870,4 @@ export {
838
870
  StepWorker
839
871
  };
840
872
 
841
- //# debugId=94F7F5AE1B4A4B8564756E2164756E21
873
+ //# debugId=6A12D877F6B3E36B64756E2164756E21
package/dist/index.js.map CHANGED
@@ -2,15 +2,15 @@
2
2
  "version": 3,
3
3
  "sources": ["../src/step-worker.ts", "../src/execution/dependency-resolver.ts", "../src/scheduling/skip-handler.ts", "../src/scheduling/step-scheduler.ts", "../src/utils/step-key.ts", "../src/scheduling/workflow-lifecycle.ts", "../src/utils/event-helpers.ts"],
4
4
  "sourcesContent": [
5
- "import { FileSystemBackend } from \"@cascade-flow/backend-filesystem\";\nimport type { Backend } from \"@cascade-flow/backend-interface\";\nimport { getMicrosecondTimestamp, MICROSECONDS_PER_MILLISECOND, convertZodToJSONSchema, projectStepState, serializeError } from \"@cascade-flow/backend-interface\";\nimport { hostname } from \"node:os\";\nimport { join } from \"node:path\";\nimport { discoverSteps, discoverWorkflows, executeStepInProcess, calculateWorkflowHash, getGitInfo, type LoadedStep } from \"@cascade-flow/runner\";\nimport { Skip } from \"@cascade-flow/workflow\";\nimport type { ZodSchema } from \"zod\";\nimport { checkDependenciesSatisfied, loadDependencyOutputs } from \"./execution/dependency-resolver.ts\";\nimport { cascadeSkip, handleStepSkip } from \"./scheduling/skip-handler.ts\";\nimport { scheduleDownstreamSteps, scheduleStep } from \"./scheduling/step-scheduler.ts\";\nimport { createStepKey, extractStepId } from \"./utils/step-key.ts\";\nimport {\n handleWorkflowCompletion,\n handleWorkflowFailure,\n handleWorkflowStart,\n parseWorkflowInput,\n validateWorkflowInput,\n} from \"./scheduling/workflow-lifecycle.ts\";\nimport type { StepWorkerOptions, StepWorkerStats } from \"./types.ts\";\nimport {\n getRunSubmittedEvent,\n getWorkflowInputValidationEvent,\n getWorkflowTerminalState,\n hasWorkflowStarted,\n hasWorkflowSubmitted,\n hasWorkflowValidatedInput,\n loadWorkflowEvents\n} from \"./utils/event-helpers.ts\";\n\n/**\n * StepWorker - long-running process for step-level distributed workflow execution\n *\n * Architecture:\n * - Workers claim and execute individual steps (not entire workflows)\n * - Steps are scheduled when their dependencies complete\n * - Multiple workers can collaboratively execute steps from the same workflow\n * - Enables finer-grained parallelization and better resource utilization\n *\n * Features:\n * - Executor loop: Claims and executes scheduled steps\n * - Scheduler loop: Finds ready steps and schedules them\n * - Heartbeat loop: Sends heartbeats for running steps\n * - Reclamation loop: Detects and reclaims stale steps from crashed workers\n * - Retry support: Automatic retries with configurable delay\n * - Timeout enforcement: Abort-controlled cancellation of hung subprocesses\n * - Graceful shutdown: Waits for active steps to complete\n */\nexport class StepWorker {\n private workerId: string;\n private backend: Backend;\n private options: Required<StepWorkerOptions>;\n private running: boolean = false;\n private activeSteps: Map<string, {\n workflowSlug: string;\n runId: string;\n stepId: string;\n attemptNumber: number;\n heartbeatTimer: Timer;\n }> = new Map();\n private stats: StepWorkerStats;\n private workflowCache: Map<string, { metadata: any; steps: LoadedStep[]; inputSchema?: ZodSchema }> = new Map();\n\n constructor(backend?: Backend, options: StepWorkerOptions = {}) {\n // Generate worker ID if not provided (using microseconds for consistency)\n this.workerId = options.workerId || `step-worker-${hostname()}-${process.pid}-${getMicrosecondTimestamp()}`;\n\n // Use provided backend or create filesystem backend\n this.backend = backend || new FileSystemBackend(options.baseDir || \"./.runs\");\n\n // Set defaults for all options\n this.options = {\n workerId: this.workerId,\n mode: options.mode ?? \"unified\",\n concurrency: options.concurrency ?? 1,\n pollInterval: options.pollInterval ?? 1000,\n heartbeatInterval: options.heartbeatInterval ?? 5000,\n staleThreshold: options.staleThreshold ?? 30000,\n staleCheckInterval: options.staleCheckInterval ?? 10000,\n schedulerInterval: options.schedulerInterval ?? 5000,\n shutdownTimeout: options.shutdownTimeout ?? 30000,\n workflowsDir: options.workflowsDir || \"./workflows\",\n baseDir: options.baseDir || \"./.runs\",\n };\n\n this.stats = {\n workerId: this.workerId,\n mode: this.options.mode,\n startedAt: getMicrosecondTimestamp(), // Convert to microseconds\n totalStepsProcessed: 0,\n currentlyRunning: 0,\n failedSteps: 0,\n reclaimedSteps: 0,\n };\n }\n\n /**\n * Get current worker statistics\n */\n getStats(): StepWorkerStats {\n return { ...this.stats };\n }\n\n /**\n * Start the worker (blocking operation)\n *\n * Starts appropriate loops based on worker mode:\n * - unified: All 4 loops (executor, scheduler, heartbeat, reclamation)\n * - executor: Only executor + heartbeat loops\n * - scheduler: Only scheduler + reclamation loops\n */\n async start(): Promise<void> {\n if (this.running) {\n throw new Error(\"Worker is already running\");\n }\n\n this.running = true;\n console.log(`[StepWorker ${this.workerId}] Starting in ${this.options.mode} mode...`);\n\n // Set up signal handlers for graceful shutdown\n this.setupSignalHandlers();\n\n // Load workflow metadata and cache it\n console.log(`[StepWorker ${this.workerId}] Loading workflows from ${this.options.workflowsDir}...`);\n await this.loadWorkflows();\n\n // Register workflows with backend\n console.log(`[StepWorker ${this.workerId}] Registering workflows with backend...`);\n await this.registerWorkflows();\n\n // Start appropriate loops based on mode\n const loops: Promise<void>[] = [];\n\n if (this.options.mode === \"unified\" || this.options.mode === \"executor\") {\n // Executor loop: Claims and executes scheduled steps\n loops.push(this.executorLoop());\n console.log(`[StepWorker ${this.workerId}] Executor loop started (concurrency: ${this.options.concurrency})`);\n }\n\n if (this.options.mode === \"unified\" || this.options.mode === \"scheduler\") {\n // Scheduler loop: Finds ready steps and schedules them\n loops.push(this.schedulerLoop());\n console.log(`[StepWorker ${this.workerId}] Scheduler loop started (interval: ${this.options.schedulerInterval}ms)`);\n\n // Reclamation loop: Detects and reclaims stale steps\n loops.push(this.reclamationLoop());\n console.log(`[StepWorker ${this.workerId}] Reclamation loop started (threshold: ${this.options.staleThreshold}ms)`);\n }\n\n console.log(`[StepWorker ${this.workerId}] Started successfully`);\n\n // Wait for all loops to complete (on shutdown)\n try {\n await Promise.all(loops);\n } finally {\n clearInterval(this.heartbeatTimer as any);\n console.log(`[StepWorker ${this.workerId}] Stopped`);\n }\n }\n\n /**\n * Gracefully stop the worker\n * Waits for active steps to complete before shutting down\n */\n async stop(): Promise<void> {\n if (!this.running) {\n return;\n }\n\n console.log(`[StepWorker ${this.workerId}] Stopping... (${this.activeSteps.size} active steps)`);\n this.running = false;\n\n // Wait for active steps to complete (with timeout)\n const shutdownStart = Date.now();\n while (this.activeSteps.size > 0 && Date.now() - shutdownStart < this.options.shutdownTimeout) {\n await new Promise((resolve) => setTimeout(resolve, 100));\n }\n\n if (this.activeSteps.size > 0) {\n console.warn(`[StepWorker ${this.workerId}] Forced shutdown with ${this.activeSteps.size} active steps`);\n }\n\n console.log(`[StepWorker ${this.workerId}] Stopped`);\n }\n\n /**\n * Load and cache workflow metadata and steps\n */\n private async loadWorkflows(): Promise<void> {\n try {\n const workflows = await discoverWorkflows(this.options.workflowsDir);\n\n for (const workflow of workflows) {\n const steps = await discoverSteps(workflow.stepsDir);\n this.workflowCache.set(workflow.slug, {\n metadata: workflow,\n steps,\n inputSchema: workflow.inputSchema, // Cache Zod schema for validation\n });\n }\n\n console.log(`[StepWorker ${this.workerId}] Loaded ${workflows.length} workflows`);\n } catch (error) {\n console.error(`[StepWorker ${this.workerId}] Failed to load workflows:`, error);\n throw error;\n }\n }\n\n /**\n * Register workflows with backend\n * Converts Zod schemas to JSON Schema and stores workflow metadata\n */\n private async registerWorkflows(): Promise<void> {\n try {\n for (const [slug, { metadata, steps, inputSchema }] of this.workflowCache) {\n // Convert Zod schema to JSON Schema if present\n let inputSchemaJSON = undefined;\n if (inputSchema) {\n try {\n inputSchemaJSON = convertZodToJSONSchema(inputSchema);\n } catch (error) {\n console.warn(\n `[StepWorker ${this.workerId}] Failed to convert schema for workflow ${slug}: ${error}`\n );\n }\n }\n\n // Build step definitions array\n const stepDefinitions = steps.map((step) => ({\n id: step.id, // Unique identifier (directory name)\n name: step.name, // Display name\n dependencies: Object.values(step.dependencies).map(dep => dep.id), // Use IDs for references\n exportOutput: step.exportOutput ?? false,\n }));\n\n // Register with backend\n await this.backend.registerWorkflow({\n slug,\n name: metadata.name,\n location: metadata.dir, // Filesystem directory path\n inputSchemaJSON,\n steps: stepDefinitions,\n });\n\n // Create workflow version\n const versionId = await calculateWorkflowHash(metadata);\n const git = await getGitInfo(metadata.dir);\n const stepManifest = steps.map((s) => s.id);\n\n await this.backend.createWorkflowVersion({\n workflowSlug: slug,\n versionId,\n createdAt: getMicrosecondTimestamp(),\n stepManifest,\n totalSteps: steps.length,\n git,\n });\n }\n\n console.log(`[StepWorker ${this.workerId}] Registered ${this.workflowCache.size} workflows`);\n } catch (error) {\n console.error(`[StepWorker ${this.workerId}] Failed to register workflows:`, error);\n throw error;\n }\n }\n\n /**\n * Executor loop: Claims and executes scheduled steps\n */\n private async executorLoop(): Promise<void> {\n while (this.running) {\n try {\n // Check if we have capacity to execute more steps\n if (this.activeSteps.size >= this.options.concurrency) {\n await new Promise((resolve) => setTimeout(resolve, this.options.pollInterval));\n continue;\n }\n\n // List scheduled steps available for claiming\n const limit = this.options.concurrency - this.activeSteps.size;\n const scheduledSteps = await this.backend.listScheduledSteps({ limit });\n\n if (scheduledSteps.length === 0) {\n // No steps available, wait before polling again\n await new Promise((resolve) => setTimeout(resolve, this.options.pollInterval));\n continue;\n }\n\n // Try to claim and execute each step (up to concurrency limit)\n for (const { workflowSlug, runId, stepId } of scheduledSteps) {\n if (this.activeSteps.size >= this.options.concurrency) {\n break;\n }\n\n // Check if step is still claimable (might have been claimed by another worker)\n const isClaimable = await this.backend.isStepClaimable(workflowSlug, runId, stepId);\n\n if (!isClaimable) {\n continue; // Already claimed or no longer scheduled\n }\n\n // Execute step (non-blocking - fires and forgets)\n this.executeStep(workflowSlug, runId, stepId).catch((err) => {\n console.error(`[StepWorker ${this.workerId}] Error executing ${createStepKey(workflowSlug, runId, stepId)}:`, err);\n });\n }\n } catch (error) {\n console.error(`[StepWorker ${this.workerId}] Error in executor loop:`, error);\n await new Promise((resolve) => setTimeout(resolve, this.options.pollInterval));\n }\n }\n }\n\n /**\n * Scheduler loop: Finds ready steps and schedules them\n */\n private async schedulerLoop(): Promise<void> {\n while (this.running) {\n try {\n // List active workflows (workflows with incomplete runs)\n const activeWorkflows = await this.backend.listActiveWorkflows();\n\n for (const workflowSlug of activeWorkflows) {\n // Get workflow from cache\n const workflowData = this.workflowCache.get(workflowSlug);\n if (!workflowData) {\n console.warn(`[StepWorker ${this.workerId}] Workflow ${workflowSlug} not in cache, skipping`);\n continue;\n }\n\n // Get all runs for this workflow\n let runIds: string[] = [];\n try {\n runIds = await this.backend.listRunIds(workflowSlug);\n } catch {\n // Failed to list runs\n continue;\n }\n\n for (const runId of runIds) {\n try {\n // Load workflow events to check run state\n const workflowEvents = await loadWorkflowEvents(this.backend, workflowSlug, runId);\n if (workflowEvents.length === 0) continue;\n\n // Check if workflow is already in a terminal state\n const { hasCompleted, hasFailed, hasCancelled } = getWorkflowTerminalState(workflowEvents);\n\n if (hasCompleted || hasFailed || hasCancelled) {\n continue; // Skip terminal workflows\n }\n\n // Check if workflow has been submitted but not started yet\n const hasSubmitted = hasWorkflowSubmitted(workflowEvents);\n const hasStarted = hasWorkflowStarted(workflowEvents);\n\n if (!hasSubmitted) {\n continue; // Skip workflows without RunSubmitted (shouldn't happen)\n }\n\n // If submitted but not started, emit WorkflowStarted event\n if (!hasStarted) {\n const runSubmittedEvent = getRunSubmittedEvent(workflowEvents);\n if (!runSubmittedEvent) {\n throw new Error(`No RunSubmitted event found for ${workflowSlug}/${runId}`);\n }\n\n await handleWorkflowStart(this.backend, workflowSlug, runId, {\n versionId: runSubmittedEvent.versionId,\n hasInputSchema: workflowData.inputSchema !== undefined,\n hasInput: !!(runSubmittedEvent && runSubmittedEvent.input !== undefined),\n }, workflowEvents);\n\n console.log(`[StepWorker ${this.workerId}] Started workflow ${workflowSlug}/${runId}`);\n }\n\n // Validate input (if not already validated)\n const hasValidatedInput = hasWorkflowValidatedInput(workflowEvents);\n\n if (!hasValidatedInput) {\n const workflowInput = parseWorkflowInput(workflowEvents);\n const validationResult = await validateWorkflowInput(\n this.backend,\n workflowSlug,\n runId,\n workflowInput,\n workflowData.inputSchema,\n workflowEvents\n );\n\n if (!validationResult.success) {\n console.log(\n `[StepWorker ${this.workerId}] Workflow ${workflowSlug}/${runId} failed (input validation)`\n );\n continue; // Skip to next run, don't schedule any steps\n }\n }\n\n // Track completion state\n let allStepsCompleted = true;\n let anyStepFailed = false;\n let failedStepName: string | undefined;\n\n // For each step in the workflow, check if it should be scheduled\n for (const step of workflowData.steps) {\n // Load step events (using stepId for event filtering)\n const stepEvents = await this.backend.loadEvents(workflowSlug, runId, {\n category: \"step\",\n stepId: step.id,\n });\n\n // If step has no events yet, it's pending\n if (stepEvents.length === 0) {\n allStepsCompleted = false;\n\n // Check if dependencies are satisfied\n const canSchedule = await checkDependenciesSatisfied(step, this.backend, workflowSlug, runId);\n\n // If no dependencies (initial step) or all deps completed, schedule it\n if (canSchedule) {\n await scheduleStep(\n this.backend,\n workflowSlug,\n runId,\n step.id,\n Object.keys(step.dependencies).length === 0 ? \"initial\" : \"dependency-satisfied\",\n 1\n );\n\n console.log(`[StepWorker ${this.workerId}] Scheduled ${step.name} in ${workflowSlug}/${runId}`);\n }\n } else {\n // Step has events, check its state\n const state = projectStepState(stepEvents, workflowSlug);\n\n if (state.status === \"pending\") {\n allStepsCompleted = false;\n\n // Check if dependencies are satisfied\n const canSchedule = await checkDependenciesSatisfied(step, this.backend, workflowSlug, runId);\n\n if (canSchedule) {\n await scheduleStep(this.backend, workflowSlug, runId, step.id, \"dependency-satisfied\", 1);\n\n console.log(\n `[StepWorker ${this.workerId}] Scheduled pending step ${step.name} in ${workflowSlug}/${runId}`\n );\n }\n } else if (state.status === \"failed\" && state.terminal) {\n anyStepFailed = true;\n failedStepName = step.name;\n allStepsCompleted = false;\n } else if (state.status !== \"completed\" && state.status !== \"skipped\") {\n allStepsCompleted = false;\n }\n }\n }\n\n // Check for workflow completion\n if (allStepsCompleted) {\n await handleWorkflowCompletion(\n this.backend,\n workflowSlug,\n runId,\n workflowData.steps,\n workflowEvents\n );\n\n console.log(`[StepWorker ${this.workerId}] Workflow ${workflowSlug}/${runId} completed`);\n } else if (anyStepFailed) {\n await handleWorkflowFailure(\n this.backend,\n workflowSlug,\n runId,\n workflowData.steps,\n workflowEvents,\n failedStepName\n );\n\n console.log(\n `[StepWorker ${this.workerId}] Workflow ${workflowSlug}/${runId} failed (step: ${failedStepName})`\n );\n }\n } catch (error) {\n console.error(`[StepWorker ${this.workerId}] Error processing run ${runId}:`, error);\n }\n }\n }\n\n await new Promise((resolve) => setTimeout(resolve, this.options.schedulerInterval));\n } catch (error) {\n console.error(`[StepWorker ${this.workerId}] Error in scheduler loop:`, error);\n await new Promise((resolve) => setTimeout(resolve, this.options.schedulerInterval));\n }\n }\n }\n\n /**\n * Reclamation loop: Detects and reclaims stale steps from crashed workers\n */\n private async reclamationLoop(): Promise<void> {\n while (this.running) {\n try {\n const reclaimed = await this.backend.reclaimStaleSteps(\n this.options.staleThreshold * 1000, // Convert to microseconds\n this.workerId\n );\n\n if (reclaimed.length > 0) {\n console.log(`[StepWorker ${this.workerId}] Reclaimed ${reclaimed.length} stale steps`);\n this.stats.reclaimedSteps += reclaimed.length;\n }\n\n await new Promise((resolve) => setTimeout(resolve, this.options.staleCheckInterval));\n } catch (error) {\n console.error(`[StepWorker ${this.workerId}] Error in reclamation loop:`, error);\n await new Promise((resolve) => setTimeout(resolve, this.options.staleCheckInterval));\n }\n }\n }\n\n /**\n * Execute a single step\n */\n private async executeStep(workflowSlug: string, runId: string, stepId: string): Promise<void> {\n const stepKey = createStepKey(workflowSlug, runId, stepId);\n let startTime = getMicrosecondTimestamp(); // Microseconds - declare at function scope\n let attemptNumber: number | null = null;\n let heartbeatTimer: Timer | null = null;\n\n try {\n // Get workflow and step metadata\n const workflowData = this.workflowCache.get(workflowSlug);\n if (!workflowData) {\n throw new Error(`Workflow ${workflowSlug} not found in cache`);\n }\n\n const step = workflowData.steps.find((s) => s.id === stepId);\n if (!step) {\n throw new Error(`Step ${stepId} not found in workflow ${workflowSlug}`);\n }\n\n // Atomically claim the step (using stepId)\n // Note: attemptNumber in metadata is a placeholder - backend will determine actual attempt number from step state\n const claimResult = await this.backend.claimScheduledStep(workflowSlug, runId, stepId, this.workerId, {\n dependencies: Object.keys(step.dependencies),\n timestamp: startTime,\n attemptNumber: 1, // Placeholder - backend determines actual attempt from step events\n });\n\n if (!claimResult) {\n console.log(`[StepWorker ${this.workerId}] Skipped ${stepKey} (already claimed)`);\n return;\n }\n\n attemptNumber = claimResult.attemptNumber;\n startTime = getMicrosecondTimestamp(); // Update startTime closer to actual execution\n\n // Track active step and start heartbeat (using stepId)\n heartbeatTimer = setInterval(() => {\n if (attemptNumber === null) return;\n this.backend.saveStepHeartbeat(workflowSlug, runId, stepId, this.workerId, attemptNumber).catch((err) => {\n console.error(`[StepWorker ${this.workerId}] Error sending heartbeat for ${stepKey}:`, err);\n });\n }, this.options.heartbeatInterval);\n\n const trackedTimer = heartbeatTimer!;\n\n this.activeSteps.set(stepKey, {\n workflowSlug,\n runId,\n stepId,\n attemptNumber,\n heartbeatTimer: trackedTimer,\n });\n\n this.stats.currentlyRunning++;\n\n console.log(`[StepWorker ${this.workerId}] Executing ${step.name} (attempt ${attemptNumber})`);\n\n // Load dependency outputs\n const dependencyOutputs = await loadDependencyOutputs(step, this.backend, workflowSlug, runId);\n\n // Load workflow input from RunSubmitted event (pre-validated by scheduler)\n const workflowEvents = await loadWorkflowEvents(this.backend, workflowSlug, runId);\n const runSubmittedEvent = getRunSubmittedEvent(workflowEvents);\n let workflowInput: unknown = undefined;\n\n if (runSubmittedEvent && runSubmittedEvent.input !== undefined) {\n // Parse input from event\n workflowInput = JSON.parse(runSubmittedEvent.input);\n }\n\n // If workflow has schema and validation succeeded, apply defaults (even when no input provided)\n if (workflowData.inputSchema) {\n const validationEvent = getWorkflowInputValidationEvent(workflowEvents);\n if (validationEvent && validationEvent.success) {\n // Re-parse with schema to get defaults (validation already confirmed this will succeed)\n // Use {} as fallback when no input provided to trigger Zod's default values\n const parseResult = workflowData.inputSchema.safeParse(workflowInput ?? {});\n if (parseResult.success) {\n workflowInput = parseResult.data;\n }\n }\n }\n\n // Build context (use step.name for display name in logs)\n const ctx = {\n runId,\n workflow: {\n slug: workflowSlug,\n name: workflowData.metadata.name,\n },\n input: workflowInput,\n log: (...args: any[]) => {\n console.log(`[${step.name}]`, ...args);\n },\n };\n\n // Execute step in subprocess with timeout\n // Priority: step timeout (most specific) → submission timeout → default 5 minutes\n const stepFile = join(step.dir, \"step.ts\");\n const submissionTimeoutMs = runSubmittedEvent && runSubmittedEvent.timeoutUs\n ? Math.floor(runSubmittedEvent.timeoutUs / 1000)\n : undefined;\n const timeout = step.timeoutMs ?? submissionTimeoutMs ?? 300000;\n\n const abortController = new AbortController();\n const executionPromise = executeStepInProcess(\n stepFile,\n step.id, // Pass step ID for stable file paths\n dependencyOutputs,\n ctx,\n attemptNumber!,\n this.backend,\n // Real-time log emission callback\n async (log) => {\n // Create LogEntry event - use log.timestamp to preserve exact ordering\n const logEvent: Omit<import(\"@cascade-flow/backend-interface\").LogEntryEvent, \"eventId\"> = {\n workflowSlug,\n runId,\n category: \"step\",\n type: \"LogEntry\",\n stepId,\n stream: log.stream,\n message: log.message,\n attemptNumber: attemptNumber!,\n timestampUs: log.timestamp, // Use the timestamp captured by subprocess executor\n };\n await this.backend.appendEvent(workflowSlug, runId, logEvent as any);\n },\n {\n signal: abortController.signal,\n }\n );\n\n const timeoutTimer = setTimeout(() => {\n abortController.abort(new Error(`Step timeout after ${timeout}ms`));\n }, timeout);\n\n const { result: output } = await executionPromise.finally(() => {\n clearTimeout(timeoutTimer);\n });\n\n const endTime = getMicrosecondTimestamp(); // Microseconds\n const duration = endTime - startTime;\n\n // Logs are already emitted in real-time via the onLog callback\n // No need to emit them again here\n\n // Emit StepCompleted event (using stepId)\n await this.backend.saveStepComplete(\n workflowSlug,\n runId,\n stepId,\n output,\n {\n timestamp: endTime,\n duration,\n attemptNumber: attemptNumber!,\n output,\n },\n step.exportOutput ?? false\n );\n\n console.log(`[StepWorker ${this.workerId}] Completed ${step.name}`);\n\n // Cleanup\n if (heartbeatTimer) {\n clearInterval(heartbeatTimer);\n heartbeatTimer = null;\n }\n this.activeSteps.delete(stepKey);\n this.stats.currentlyRunning--;\n this.stats.totalStepsProcessed++;\n\n // If in unified mode, schedule downstream steps (using stepId)\n if (this.options.mode === \"unified\") {\n const workflowData = this.workflowCache.get(workflowSlug);\n if (workflowData) {\n const scheduled = await scheduleDownstreamSteps(\n this.backend,\n workflowSlug,\n runId,\n stepId,\n workflowData.steps\n );\n if (scheduled.length > 0) {\n console.log(\n `[StepWorker ${this.workerId}] Scheduled downstream steps: ${scheduled.join(\", \")}`\n );\n }\n }\n }\n } catch (error) {\n const failureContext = attemptNumber === null ? \"Failed to claim\" : \"Failed\";\n console.error(`[StepWorker ${this.workerId}] ${failureContext} ${stepKey}:`, error);\n\n const activeStep = this.activeSteps.get(stepKey);\n if (activeStep) {\n clearInterval(activeStep.heartbeatTimer);\n this.activeSteps.delete(stepKey);\n this.stats.currentlyRunning--;\n } else if (heartbeatTimer) {\n clearInterval(heartbeatTimer);\n heartbeatTimer = null;\n }\n\n if (attemptNumber === null) {\n return;\n }\n\n this.stats.failedSteps++;\n\n // Get workflow and step metadata for retry logic\n const workflowData = this.workflowCache.get(workflowSlug);\n if (!workflowData) {\n console.error(`[StepWorker ${this.workerId}] Workflow ${workflowSlug} not found in cache`);\n return;\n }\n\n // Extract stepId from stepKey (handles nested steps with slashes)\n const stepId = extractStepId(stepKey);\n if (!stepId) {\n console.error(`[StepWorker ${this.workerId}] Invalid stepKey format: ${stepKey}`);\n return;\n }\n const step = workflowData.steps.find((s) => s.id === stepId);\n if (!step) {\n console.error(`[StepWorker ${this.workerId}] Step ${stepId} not found in workflow ${workflowSlug}`);\n return;\n }\n\n // Load step events to get current attempt number (using stepId)\n const events = await this.backend.loadEvents(workflowSlug, runId, { category: \"step\", stepId });\n const state = projectStepState(events, workflowSlug);\n const currentAttemptNumber = state.attemptNumber;\n\n const endTime = getMicrosecondTimestamp(); // Microseconds\n const duration = endTime - (state.startTime || startTime);\n\n // Prepare error object using centralized error serialization\n const stepError = serializeError(error);\n\n // SKIP DETECTION: Check if error is a Skip (don't retry, just mark as skipped)\n if (error instanceof Error && (error.name === \"Skip\" || error instanceof Skip)) {\n const skipError = error as Skip;\n\n await handleStepSkip(this.backend, workflowSlug, runId, stepId, skipError, duration, currentAttemptNumber);\n\n console.log(`[StepWorker ${this.workerId}] Skipped ${step.name}: ${skipError.reason || skipError.message}`);\n\n // If in unified mode, check for cascade skips\n if (this.options.mode === \"unified\") {\n const workflowData = this.workflowCache.get(workflowSlug);\n if (workflowData) {\n await cascadeSkip(this.backend, workflowSlug, runId, stepId, workflowData.steps, this.workerId);\n }\n }\n\n return; // Don't retry, don't mark as failed\n }\n\n // Check if we should retry\n const maxRetries = step.maxRetries ?? 0;\n if (currentAttemptNumber <= maxRetries) {\n // Not terminal - schedule retry atomically\n const retryDelayMs = step.retryDelayMs ?? 0;\n const nextRetryAt = getMicrosecondTimestamp() + retryDelayMs * MICROSECONDS_PER_MILLISECOND;\n\n // Use atomic method to ensure both failure and schedule events are written together\n await this.backend.saveStepFailedAndScheduleRetry(\n workflowSlug,\n runId,\n stepId,\n stepError,\n {\n duration,\n attemptNumber: currentAttemptNumber,\n nextRetryAt,\n failureReason: \"execution-error\",\n },\n {\n availableAt: nextRetryAt,\n nextAttemptNumber: currentAttemptNumber + 1,\n retryDelayMs,\n maxRetries,\n }\n );\n\n console.log(\n `[StepWorker ${this.workerId}] Scheduled retry for ${step.name} (attempt ${currentAttemptNumber + 1}/${maxRetries + 1})`\n );\n } else {\n // Terminal failure - retries exhausted\n await this.backend.saveStepFailed(workflowSlug, runId, stepId, stepError, {\n duration,\n attemptNumber: currentAttemptNumber,\n terminal: true,\n failureReason: \"exhausted-retries\",\n });\n\n console.log(`[StepWorker ${this.workerId}] Terminal failure for ${step.name} (retries exhausted)`);\n }\n }\n }\n\n /**\n * Set up signal handlers for graceful shutdown\n */\n private setupSignalHandlers(): void {\n const shutdown = async (signal: string) => {\n console.log(`[StepWorker ${this.workerId}] Received ${signal}, shutting down gracefully...`);\n await this.stop();\n process.exit(0);\n };\n\n process.on(\"SIGTERM\", () => shutdown(\"SIGTERM\"));\n process.on(\"SIGINT\", () => shutdown(\"SIGINT\"));\n }\n\n private heartbeatTimer?: Timer;\n}\n",
6
- "import type { Backend } from \"@cascade-flow/backend-interface\";\nimport { projectStepState } from \"@cascade-flow/backend-interface\";\nimport { type LoadedStep } from \"@cascade-flow/runner\";\nimport { isOptional } from \"@cascade-flow/workflow\";\nimport { loadStepState } from \"../utils/event-helpers.ts\";\n\n/**\n * Check if all dependencies for a step are satisfied\n * Returns true if the step can be scheduled\n */\nexport async function checkDependenciesSatisfied(\n step: LoadedStep,\n backend: Backend,\n workflowSlug: string,\n runId: string\n): Promise<boolean> {\n for (const [depKey, dep] of Object.entries(step.dependencies) as [string, LoadedStep][]) {\n const depEvents = await backend.loadEvents(workflowSlug, runId, {\n category: \"step\",\n stepId: dep.id,\n });\n\n // If dependency has no events yet\n if (depEvents.length === 0) {\n const isOptionalDep = isOptional(step.dependencies[depKey]);\n if (!isOptionalDep) {\n return false; // Required dependency not ready\n }\n // Optional deps can be missing, continue checking others\n continue;\n }\n\n const depState = projectStepState(depEvents as any, workflowSlug);\n const isOptionalDep = isOptional(step.dependencies[depKey]);\n\n // Required deps must be completed, optional deps can be skipped\n if (depState.status === \"skipped\" && isOptionalDep) {\n continue; // OK, optional and skipped\n }\n\n if (depState.status !== \"completed\") {\n return false; // Dependency not completed\n }\n }\n\n return true; // All dependencies satisfied\n}\n\n/**\n * Load outputs from all dependencies\n * Returns a map of dependency alias to output value\n */\nexport async function loadDependencyOutputs(\n step: LoadedStep,\n backend: Backend,\n workflowSlug: string,\n runId: string\n): Promise<Record<string, any>> {\n const dependencyOutputs: Record<string, any> = {};\n\n for (const [depKey, depStep] of Object.entries(step.dependencies) as [string, LoadedStep][]) {\n const depEvents = await backend.loadEvents(workflowSlug, runId, {\n category: \"step\",\n stepId: depStep.id,\n });\n\n if (depEvents.length === 0) {\n const isOptionalDep = isOptional(step.dependencies[depKey]);\n if (!isOptionalDep) {\n throw new Error(`Required dependency ${depStep.name} has no events`);\n }\n dependencyOutputs[depKey] = undefined;\n continue;\n }\n\n const depState = projectStepState(depEvents as any, workflowSlug);\n const isOptionalDep = isOptional(step.dependencies[depKey]);\n\n // Optional deps can be skipped\n if (depState.status === \"skipped\" && isOptionalDep) {\n dependencyOutputs[depKey] = undefined;\n continue;\n }\n\n if (depState.status !== \"completed\" || !depState.output) {\n throw new Error(`Dependency ${depStep.name} is not completed`);\n }\n\n // Parse dependency output\n dependencyOutputs[depKey] = JSON.parse(depState.output);\n }\n\n return dependencyOutputs;\n}\n\n/**\n * Find all steps that depend on a given step\n * @param targetStepId - The stepId (unique identifier) to find dependents for\n * @param allSteps - All steps in the workflow\n * @param requiredOnly - If true, only return steps with required dependencies\n */\nexport function findDependentSteps(\n targetStepId: string,\n allSteps: LoadedStep[],\n requiredOnly: boolean = false\n): LoadedStep[] {\n return allSteps.filter((step) => {\n const deps = Object.entries(step.dependencies) as [string, LoadedStep][];\n return deps.some(([alias, dep]) => {\n const dependsOnTarget = dep.id === targetStepId;\n if (!dependsOnTarget) return false;\n\n if (requiredOnly) {\n const isOptionalDep = isOptional(step.dependencies[alias]);\n return !isOptionalDep; // Only include if it's a required dependency\n }\n\n return true; // Include all dependencies\n });\n });\n}\n",
5
+ "import { FileSystemBackend } from \"@cascade-flow/backend-filesystem\";\nimport type { Backend } from \"@cascade-flow/backend-interface\";\nimport { getMicrosecondTimestamp, MICROSECONDS_PER_MILLISECOND, convertZodToJSONSchema, projectStepState, serializeError } from \"@cascade-flow/backend-interface\";\nimport { hostname } from \"node:os\";\nimport { join } from \"node:path\";\nimport { discoverSteps, discoverWorkflows, executeStepInProcess, calculateWorkflowHash, getGitInfo, type LoadedStep, type CheckpointData, type CheckpointFailedData } from \"@cascade-flow/runner\";\nimport { Skip } from \"@cascade-flow/workflow\";\nimport type { ZodSchema } from \"zod\";\nimport { checkDependenciesSatisfied, loadDependencyOutputs } from \"./execution/dependency-resolver.ts\";\nimport { cascadeSkip, handleStepSkip } from \"./scheduling/skip-handler.ts\";\nimport { scheduleDownstreamSteps, scheduleStep } from \"./scheduling/step-scheduler.ts\";\nimport { createStepKey, extractStepId } from \"./utils/step-key.ts\";\nimport {\n handleWorkflowCompletion,\n handleWorkflowFailure,\n handleWorkflowStart,\n parseWorkflowInput,\n validateWorkflowInput,\n} from \"./scheduling/workflow-lifecycle.ts\";\nimport type { StepWorkerOptions, StepWorkerStats } from \"./types.ts\";\nimport {\n getRunSubmittedEvent,\n getWorkflowInputValidationEvent,\n getWorkflowTerminalState,\n hasWorkflowStarted,\n hasWorkflowSubmitted,\n hasWorkflowValidatedInput,\n loadWorkflowEvents\n} from \"./utils/event-helpers.ts\";\n\n/**\n * StepWorker - long-running process for step-level distributed workflow execution\n *\n * Architecture:\n * - Workers claim and execute individual steps (not entire workflows)\n * - Steps are scheduled when their dependencies complete\n * - Multiple workers can collaboratively execute steps from the same workflow\n * - Enables finer-grained parallelization and better resource utilization\n *\n * Features:\n * - Executor loop: Claims and executes scheduled steps\n * - Scheduler loop: Finds ready steps and schedules them\n * - Heartbeat loop: Sends heartbeats for running steps\n * - Reclamation loop: Detects and reclaims stale steps from crashed workers\n * - Retry support: Automatic retries with configurable delay\n * - Timeout enforcement: Abort-controlled cancellation of hung subprocesses\n * - Graceful shutdown: Waits for active steps to complete\n */\nexport class StepWorker {\n private workerId: string;\n private backend: Backend;\n private options: Required<StepWorkerOptions>;\n private running: boolean = false;\n private activeSteps: Map<string, {\n workflowSlug: string;\n runId: string;\n stepId: string;\n attemptNumber: number;\n heartbeatTimer: Timer;\n }> = new Map();\n private stats: StepWorkerStats;\n private workflowCache: Map<string, { metadata: any; steps: LoadedStep[]; inputSchema?: ZodSchema }> = new Map();\n\n constructor(backend?: Backend, options: StepWorkerOptions = {}) {\n // Generate worker ID if not provided (using microseconds for consistency)\n this.workerId = options.workerId || `step-worker-${hostname()}-${process.pid}-${getMicrosecondTimestamp()}`;\n\n // Use provided backend or create filesystem backend\n this.backend = backend || new FileSystemBackend(options.baseDir || \"./.runs\");\n\n // Set defaults for all options\n this.options = {\n workerId: this.workerId,\n mode: options.mode ?? \"unified\",\n concurrency: options.concurrency ?? 1,\n pollInterval: options.pollInterval ?? 1000,\n heartbeatInterval: options.heartbeatInterval ?? 5000,\n staleThreshold: options.staleThreshold ?? 30000,\n staleCheckInterval: options.staleCheckInterval ?? 10000,\n schedulerInterval: options.schedulerInterval ?? 5000,\n shutdownTimeout: options.shutdownTimeout ?? 30000,\n workflowsDir: options.workflowsDir || \"./workflows\",\n baseDir: options.baseDir || \"./.runs\",\n };\n\n this.stats = {\n workerId: this.workerId,\n mode: this.options.mode,\n startedAt: getMicrosecondTimestamp(), // Convert to microseconds\n totalStepsProcessed: 0,\n currentlyRunning: 0,\n failedSteps: 0,\n reclaimedSteps: 0,\n };\n }\n\n /**\n * Get current worker statistics\n */\n getStats(): StepWorkerStats {\n return { ...this.stats };\n }\n\n /**\n * Start the worker (blocking operation)\n *\n * Starts appropriate loops based on worker mode:\n * - unified: All 4 loops (executor, scheduler, heartbeat, reclamation)\n * - executor: Only executor + heartbeat loops\n * - scheduler: Only scheduler + reclamation loops\n */\n async start(): Promise<void> {\n if (this.running) {\n throw new Error(\"Worker is already running\");\n }\n\n this.running = true;\n console.log(`[StepWorker ${this.workerId}] Starting in ${this.options.mode} mode...`);\n\n // Set up signal handlers for graceful shutdown\n this.setupSignalHandlers();\n\n // Load workflow metadata and cache it\n console.log(`[StepWorker ${this.workerId}] Loading workflows from ${this.options.workflowsDir}...`);\n await this.loadWorkflows();\n\n // Register workflows with backend\n console.log(`[StepWorker ${this.workerId}] Registering workflows with backend...`);\n await this.registerWorkflows();\n\n // Start appropriate loops based on mode\n const loops: Promise<void>[] = [];\n\n if (this.options.mode === \"unified\" || this.options.mode === \"executor\") {\n // Executor loop: Claims and executes scheduled steps\n loops.push(this.executorLoop());\n console.log(`[StepWorker ${this.workerId}] Executor loop started (concurrency: ${this.options.concurrency})`);\n }\n\n if (this.options.mode === \"unified\" || this.options.mode === \"scheduler\") {\n // Scheduler loop: Finds ready steps and schedules them\n loops.push(this.schedulerLoop());\n console.log(`[StepWorker ${this.workerId}] Scheduler loop started (interval: ${this.options.schedulerInterval}ms)`);\n\n // Reclamation loop: Detects and reclaims stale steps\n loops.push(this.reclamationLoop());\n console.log(`[StepWorker ${this.workerId}] Reclamation loop started (threshold: ${this.options.staleThreshold}ms)`);\n }\n\n console.log(`[StepWorker ${this.workerId}] Started successfully`);\n\n // Wait for all loops to complete (on shutdown)\n try {\n await Promise.all(loops);\n } finally {\n clearInterval(this.heartbeatTimer as any);\n console.log(`[StepWorker ${this.workerId}] Stopped`);\n }\n }\n\n /**\n * Gracefully stop the worker\n * Waits for active steps to complete before shutting down\n */\n async stop(): Promise<void> {\n if (!this.running) {\n return;\n }\n\n console.log(`[StepWorker ${this.workerId}] Stopping... (${this.activeSteps.size} active steps)`);\n this.running = false;\n\n // Wait for active steps to complete (with timeout)\n const shutdownStart = Date.now();\n while (this.activeSteps.size > 0 && Date.now() - shutdownStart < this.options.shutdownTimeout) {\n await new Promise((resolve) => setTimeout(resolve, 100));\n }\n\n if (this.activeSteps.size > 0) {\n console.warn(`[StepWorker ${this.workerId}] Forced shutdown with ${this.activeSteps.size} active steps`);\n }\n\n console.log(`[StepWorker ${this.workerId}] Stopped`);\n }\n\n /**\n * Load and cache workflow metadata and steps\n */\n private async loadWorkflows(): Promise<void> {\n try {\n const workflows = await discoverWorkflows(this.options.workflowsDir);\n\n for (const workflow of workflows) {\n const steps = await discoverSteps(workflow.stepsDir);\n this.workflowCache.set(workflow.slug, {\n metadata: workflow,\n steps,\n inputSchema: workflow.inputSchema, // Cache Zod schema for validation\n });\n }\n\n console.log(`[StepWorker ${this.workerId}] Loaded ${workflows.length} workflows`);\n } catch (error) {\n console.error(`[StepWorker ${this.workerId}] Failed to load workflows:`, error);\n throw error;\n }\n }\n\n /**\n * Register workflows with backend\n * Converts Zod schemas to JSON Schema and stores workflow metadata\n */\n private async registerWorkflows(): Promise<void> {\n try {\n for (const [slug, { metadata, steps, inputSchema }] of this.workflowCache) {\n // Convert Zod schema to JSON Schema if present\n let inputSchemaJSON = undefined;\n if (inputSchema) {\n try {\n inputSchemaJSON = convertZodToJSONSchema(inputSchema);\n } catch (error) {\n console.warn(\n `[StepWorker ${this.workerId}] Failed to convert schema for workflow ${slug}: ${error}`\n );\n }\n }\n\n // Build step definitions array\n const stepDefinitions = steps.map((step) => ({\n id: step.id, // Unique identifier (directory name)\n name: step.name, // Display name\n dependencies: Object.values(step.dependencies).map(dep => dep.id), // Use IDs for references\n exportOutput: step.exportOutput ?? false,\n }));\n\n // Register with backend\n await this.backend.registerWorkflow({\n slug,\n name: metadata.name,\n location: metadata.dir, // Filesystem directory path\n inputSchemaJSON,\n steps: stepDefinitions,\n });\n\n // Create workflow version\n const versionId = await calculateWorkflowHash(metadata);\n const git = await getGitInfo(metadata.dir);\n const stepManifest = steps.map((s) => s.id);\n\n await this.backend.createWorkflowVersion({\n workflowSlug: slug,\n versionId,\n createdAt: getMicrosecondTimestamp(),\n stepManifest,\n totalSteps: steps.length,\n git,\n });\n }\n\n console.log(`[StepWorker ${this.workerId}] Registered ${this.workflowCache.size} workflows`);\n } catch (error) {\n console.error(`[StepWorker ${this.workerId}] Failed to register workflows:`, error);\n throw error;\n }\n }\n\n /**\n * Executor loop: Claims and executes scheduled steps\n */\n private async executorLoop(): Promise<void> {\n while (this.running) {\n try {\n // Check if we have capacity to execute more steps\n if (this.activeSteps.size >= this.options.concurrency) {\n await new Promise((resolve) => setTimeout(resolve, this.options.pollInterval));\n continue;\n }\n\n // List scheduled steps available for claiming\n const limit = this.options.concurrency - this.activeSteps.size;\n const scheduledSteps = await this.backend.listScheduledSteps({ limit });\n\n if (scheduledSteps.length === 0) {\n // No steps available, wait before polling again\n await new Promise((resolve) => setTimeout(resolve, this.options.pollInterval));\n continue;\n }\n\n // Try to claim and execute each step (up to concurrency limit)\n for (const { workflowSlug, runId, stepId } of scheduledSteps) {\n if (this.activeSteps.size >= this.options.concurrency) {\n break;\n }\n\n // Check if step is still claimable (might have been claimed by another worker)\n const isClaimable = await this.backend.isStepClaimable(workflowSlug, runId, stepId);\n\n if (!isClaimable) {\n continue; // Already claimed or no longer scheduled\n }\n\n // Execute step (non-blocking - fires and forgets)\n this.executeStep(workflowSlug, runId, stepId).catch((err) => {\n console.error(`[StepWorker ${this.workerId}] Error executing ${createStepKey(workflowSlug, runId, stepId)}:`, err);\n });\n }\n } catch (error) {\n console.error(`[StepWorker ${this.workerId}] Error in executor loop:`, error);\n await new Promise((resolve) => setTimeout(resolve, this.options.pollInterval));\n }\n }\n }\n\n /**\n * Scheduler loop: Finds ready steps and schedules them\n */\n private async schedulerLoop(): Promise<void> {\n while (this.running) {\n try {\n // List active workflows (workflows with incomplete runs)\n const activeWorkflows = await this.backend.listActiveWorkflows();\n\n for (const workflowSlug of activeWorkflows) {\n // Get workflow from cache\n const workflowData = this.workflowCache.get(workflowSlug);\n if (!workflowData) {\n console.warn(`[StepWorker ${this.workerId}] Workflow ${workflowSlug} not in cache, skipping`);\n continue;\n }\n\n // Get all runs for this workflow\n let runIds: string[] = [];\n try {\n runIds = await this.backend.listRunIds(workflowSlug);\n } catch {\n // Failed to list runs\n continue;\n }\n\n for (const runId of runIds) {\n try {\n // Load workflow events to check run state\n const workflowEvents = await loadWorkflowEvents(this.backend, workflowSlug, runId);\n if (workflowEvents.length === 0) continue;\n\n // Check if workflow is already in a terminal state\n const { hasCompleted, hasFailed, hasCancelled } = getWorkflowTerminalState(workflowEvents);\n\n if (hasCompleted || hasFailed || hasCancelled) {\n continue; // Skip terminal workflows\n }\n\n // Check if workflow has been submitted but not started yet\n const hasSubmitted = hasWorkflowSubmitted(workflowEvents);\n const hasStarted = hasWorkflowStarted(workflowEvents);\n\n if (!hasSubmitted) {\n continue; // Skip workflows without RunSubmitted (shouldn't happen)\n }\n\n // If submitted but not started, emit WorkflowStarted event\n if (!hasStarted) {\n const runSubmittedEvent = getRunSubmittedEvent(workflowEvents);\n if (!runSubmittedEvent) {\n throw new Error(`No RunSubmitted event found for ${workflowSlug}/${runId}`);\n }\n\n await handleWorkflowStart(this.backend, workflowSlug, runId, {\n versionId: runSubmittedEvent.versionId,\n hasInputSchema: workflowData.inputSchema !== undefined,\n hasInput: !!(runSubmittedEvent && runSubmittedEvent.input !== undefined),\n }, workflowEvents);\n\n console.log(`[StepWorker ${this.workerId}] Started workflow ${workflowSlug}/${runId}`);\n }\n\n // Validate input (if not already validated)\n const hasValidatedInput = hasWorkflowValidatedInput(workflowEvents);\n\n if (!hasValidatedInput) {\n const workflowInput = parseWorkflowInput(workflowEvents);\n const validationResult = await validateWorkflowInput(\n this.backend,\n workflowSlug,\n runId,\n workflowInput,\n workflowData.inputSchema,\n workflowEvents\n );\n\n if (!validationResult.success) {\n console.log(\n `[StepWorker ${this.workerId}] Workflow ${workflowSlug}/${runId} failed (input validation)`\n );\n continue; // Skip to next run, don't schedule any steps\n }\n }\n\n // Track completion state\n let allStepsCompleted = true;\n let anyStepFailed = false;\n let failedStepName: string | undefined;\n\n // Load step events for state projection in a single batch query (avoids N+1)\n const allStepEvents = await this.backend.loadStepEventsForProjection(workflowSlug, runId);\n\n // For each step in the workflow, check if it should be scheduled\n for (const step of workflowData.steps) {\n // Get step events from batch-loaded map\n const stepEvents = allStepEvents.get(step.id) || [];\n\n // If step has no events yet, it's pending\n if (stepEvents.length === 0) {\n allStepsCompleted = false;\n\n // Check if dependencies are satisfied\n const canSchedule = await checkDependenciesSatisfied(step, this.backend, workflowSlug, runId);\n\n // If no dependencies (initial step) or all deps completed, schedule it\n if (canSchedule) {\n await scheduleStep(\n this.backend,\n workflowSlug,\n runId,\n step.id,\n Object.keys(step.dependencies).length === 0 ? \"initial\" : \"dependency-satisfied\",\n 1\n );\n\n console.log(`[StepWorker ${this.workerId}] Scheduled ${step.name} in ${workflowSlug}/${runId}`);\n }\n } else {\n // Step has events, check its state\n const state = projectStepState(stepEvents, workflowSlug);\n\n if (state.status === \"pending\") {\n allStepsCompleted = false;\n\n // Check if dependencies are satisfied\n const canSchedule = await checkDependenciesSatisfied(step, this.backend, workflowSlug, runId);\n\n if (canSchedule) {\n await scheduleStep(this.backend, workflowSlug, runId, step.id, \"dependency-satisfied\", 1);\n\n console.log(\n `[StepWorker ${this.workerId}] Scheduled pending step ${step.name} in ${workflowSlug}/${runId}`\n );\n }\n } else if (state.status === \"failed\" && state.terminal) {\n anyStepFailed = true;\n failedStepName = step.name;\n allStepsCompleted = false;\n } else if (state.status !== \"completed\" && state.status !== \"skipped\") {\n allStepsCompleted = false;\n }\n }\n }\n\n // Check for workflow completion\n if (allStepsCompleted) {\n await handleWorkflowCompletion(\n this.backend,\n workflowSlug,\n runId,\n workflowData.steps,\n workflowEvents\n );\n\n console.log(`[StepWorker ${this.workerId}] Workflow ${workflowSlug}/${runId} completed`);\n } else if (anyStepFailed) {\n await handleWorkflowFailure(\n this.backend,\n workflowSlug,\n runId,\n workflowData.steps,\n workflowEvents,\n failedStepName\n );\n\n console.log(\n `[StepWorker ${this.workerId}] Workflow ${workflowSlug}/${runId} failed (step: ${failedStepName})`\n );\n }\n } catch (error) {\n console.error(`[StepWorker ${this.workerId}] Error processing run ${runId}:`, error);\n }\n }\n }\n\n await new Promise((resolve) => setTimeout(resolve, this.options.schedulerInterval));\n } catch (error) {\n console.error(`[StepWorker ${this.workerId}] Error in scheduler loop:`, error);\n await new Promise((resolve) => setTimeout(resolve, this.options.schedulerInterval));\n }\n }\n }\n\n /**\n * Reclamation loop: Detects and reclaims stale steps from crashed workers\n */\n private async reclamationLoop(): Promise<void> {\n while (this.running) {\n try {\n const reclaimed = await this.backend.reclaimStaleSteps(\n this.options.staleThreshold * 1000, // Convert to microseconds\n this.workerId\n );\n\n if (reclaimed.length > 0) {\n console.log(`[StepWorker ${this.workerId}] Reclaimed ${reclaimed.length} stale steps`);\n this.stats.reclaimedSteps += reclaimed.length;\n }\n\n await new Promise((resolve) => setTimeout(resolve, this.options.staleCheckInterval));\n } catch (error) {\n console.error(`[StepWorker ${this.workerId}] Error in reclamation loop:`, error);\n await new Promise((resolve) => setTimeout(resolve, this.options.staleCheckInterval));\n }\n }\n }\n\n /**\n * Load existing checkpoints for a step from events\n *\n * Returns a Map from checkpoint name to array of data (by sequence number)\n */\n private async loadCheckpointsFromEvents(\n workflowSlug: string,\n runId: string,\n stepId: string\n ): Promise<Map<string, string[]>> {\n const events = await this.backend.loadEvents(workflowSlug, runId, {\n category: \"step\",\n stepId,\n });\n\n const checkpoints = new Map<string, string[]>();\n for (const event of events) {\n if (event.type === \"StepCheckpoint\") {\n if (!checkpoints.has(event.name)) {\n checkpoints.set(event.name, []);\n }\n const arr = checkpoints.get(event.name)!;\n // Ensure array is large enough for sequence number\n while (arr.length <= event.sequenceNumber) {\n arr.push(\"\");\n }\n arr[event.sequenceNumber] = event.data;\n }\n }\n return checkpoints;\n }\n\n /**\n * Execute a single step\n */\n private async executeStep(workflowSlug: string, runId: string, stepId: string): Promise<void> {\n const stepKey = createStepKey(workflowSlug, runId, stepId);\n let startTime = getMicrosecondTimestamp(); // Microseconds - declare at function scope\n let attemptNumber: number | null = null;\n let heartbeatTimer: Timer | null = null;\n\n try {\n // Get workflow and step metadata\n const workflowData = this.workflowCache.get(workflowSlug);\n if (!workflowData) {\n throw new Error(`Workflow ${workflowSlug} not found in cache`);\n }\n\n const step = workflowData.steps.find((s) => s.id === stepId);\n if (!step) {\n throw new Error(`Step ${stepId} not found in workflow ${workflowSlug}`);\n }\n\n // Atomically claim the step (using stepId)\n // Note: attemptNumber in metadata is a placeholder - backend will determine actual attempt number from step state\n const claimResult = await this.backend.claimScheduledStep(workflowSlug, runId, stepId, this.workerId, {\n dependencies: Object.keys(step.dependencies),\n timestamp: startTime,\n attemptNumber: 1, // Placeholder - backend determines actual attempt from step events\n });\n\n if (!claimResult) {\n console.log(`[StepWorker ${this.workerId}] Skipped ${stepKey} (already claimed)`);\n return;\n }\n\n attemptNumber = claimResult.attemptNumber;\n startTime = getMicrosecondTimestamp(); // Update startTime closer to actual execution\n\n // Track active step and start heartbeat (using stepId)\n heartbeatTimer = setInterval(() => {\n if (attemptNumber === null) return;\n this.backend.saveStepHeartbeat(workflowSlug, runId, stepId, this.workerId, attemptNumber).catch((err) => {\n console.error(`[StepWorker ${this.workerId}] Error sending heartbeat for ${stepKey}:`, err);\n });\n }, this.options.heartbeatInterval);\n\n const trackedTimer = heartbeatTimer!;\n\n this.activeSteps.set(stepKey, {\n workflowSlug,\n runId,\n stepId,\n attemptNumber,\n heartbeatTimer: trackedTimer,\n });\n\n this.stats.currentlyRunning++;\n\n console.log(`[StepWorker ${this.workerId}] Executing ${step.name} (attempt ${attemptNumber})`);\n\n // Load dependency outputs\n const dependencyOutputs = await loadDependencyOutputs(step, this.backend, workflowSlug, runId);\n\n // Load workflow input from RunSubmitted event (pre-validated by scheduler)\n const workflowEvents = await loadWorkflowEvents(this.backend, workflowSlug, runId);\n const runSubmittedEvent = getRunSubmittedEvent(workflowEvents);\n let workflowInput: unknown = undefined;\n\n if (runSubmittedEvent && runSubmittedEvent.input !== undefined) {\n // Parse input from event\n workflowInput = JSON.parse(runSubmittedEvent.input);\n }\n\n // If workflow has schema and validation succeeded, apply defaults (even when no input provided)\n if (workflowData.inputSchema) {\n const validationEvent = getWorkflowInputValidationEvent(workflowEvents);\n if (validationEvent && validationEvent.success) {\n // Re-parse with schema to get defaults (validation already confirmed this will succeed)\n // Use {} as fallback when no input provided to trigger Zod's default values\n const parseResult = workflowData.inputSchema.safeParse(workflowInput ?? {});\n if (parseResult.success) {\n workflowInput = parseResult.data;\n }\n }\n }\n\n // Build context (use step.name for display name in logs)\n const ctx = {\n runId,\n workflow: {\n slug: workflowSlug,\n name: workflowData.metadata.name,\n },\n input: workflowInput,\n log: (...args: any[]) => {\n console.log(`[${step.name}]`, ...args);\n },\n };\n\n // Execute step in subprocess with timeout\n // Priority: step timeout (most specific) → submission timeout → default 5 minutes\n const stepFile = join(step.dir, \"step.ts\");\n const submissionTimeoutMs = runSubmittedEvent && runSubmittedEvent.timeoutUs\n ? Math.floor(runSubmittedEvent.timeoutUs / 1000)\n : undefined;\n const timeout = step.timeoutMs ?? submissionTimeoutMs ?? 300000;\n\n // Load existing checkpoints for replay (from any previous attempts)\n const existingCheckpoints = await this.loadCheckpointsFromEvents(\n workflowSlug,\n runId,\n stepId\n );\n\n const abortController = new AbortController();\n const executionPromise = executeStepInProcess(\n stepFile,\n step.id, // Pass step ID for stable file paths\n dependencyOutputs,\n ctx,\n attemptNumber!,\n this.backend,\n // Real-time log emission callback\n async (log) => {\n // Create LogEntry event - use log.timestamp to preserve exact ordering\n const logEvent: Omit<import(\"@cascade-flow/backend-interface\").LogEntryEvent, \"eventId\"> = {\n workflowSlug,\n runId,\n category: \"step\",\n type: \"LogEntry\",\n stepId,\n stream: log.stream,\n message: log.message,\n attemptNumber: attemptNumber!,\n timestampUs: log.timestamp, // Use the timestamp captured by subprocess executor\n };\n await this.backend.appendEvent(workflowSlug, runId, logEvent as any);\n },\n // Checkpoint persistence callback\n async (checkpoint: CheckpointData) => {\n await this.backend.saveStepCheckpoint(workflowSlug, runId, stepId, {\n name: checkpoint.name,\n sequenceNumber: checkpoint.sequenceNumber,\n attemptNumber: attemptNumber!,\n data: checkpoint.data,\n });\n },\n // Checkpoint failure callback\n async (failure: CheckpointFailedData) => {\n await this.backend.saveStepCheckpointFailed(workflowSlug, runId, stepId, {\n name: failure.name,\n sequenceNumber: failure.sequenceNumber,\n attemptNumber: attemptNumber!,\n error: JSON.parse(failure.error),\n });\n },\n existingCheckpoints,\n {\n signal: abortController.signal,\n }\n );\n\n const timeoutTimer = setTimeout(() => {\n abortController.abort(new Error(`Step timeout after ${timeout}ms`));\n }, timeout);\n\n const { result: output } = await executionPromise.finally(() => {\n clearTimeout(timeoutTimer);\n });\n\n const endTime = getMicrosecondTimestamp(); // Microseconds\n const duration = endTime - startTime;\n\n // Logs are already emitted in real-time via the onLog callback\n // No need to emit them again here\n\n // Emit StepCompleted event (using stepId)\n await this.backend.saveStepComplete(\n workflowSlug,\n runId,\n stepId,\n output,\n {\n timestamp: endTime,\n duration,\n attemptNumber: attemptNumber!,\n output,\n },\n step.exportOutput ?? false\n );\n\n console.log(`[StepWorker ${this.workerId}] Completed ${step.name}`);\n\n // Cleanup\n if (heartbeatTimer) {\n clearInterval(heartbeatTimer);\n heartbeatTimer = null;\n }\n this.activeSteps.delete(stepKey);\n this.stats.currentlyRunning--;\n this.stats.totalStepsProcessed++;\n\n // If in unified mode, schedule downstream steps (using stepId)\n if (this.options.mode === \"unified\") {\n const workflowData = this.workflowCache.get(workflowSlug);\n if (workflowData) {\n const scheduled = await scheduleDownstreamSteps(\n this.backend,\n workflowSlug,\n runId,\n stepId,\n workflowData.steps\n );\n if (scheduled.length > 0) {\n console.log(\n `[StepWorker ${this.workerId}] Scheduled downstream steps: ${scheduled.join(\", \")}`\n );\n }\n }\n }\n } catch (error) {\n const failureContext = attemptNumber === null ? \"Failed to claim\" : \"Failed\";\n console.error(`[StepWorker ${this.workerId}] ${failureContext} ${stepKey}:`, error);\n\n const activeStep = this.activeSteps.get(stepKey);\n if (activeStep) {\n clearInterval(activeStep.heartbeatTimer);\n this.activeSteps.delete(stepKey);\n this.stats.currentlyRunning--;\n } else if (heartbeatTimer) {\n clearInterval(heartbeatTimer);\n heartbeatTimer = null;\n }\n\n if (attemptNumber === null) {\n return;\n }\n\n this.stats.failedSteps++;\n\n // Get workflow and step metadata for retry logic\n const workflowData = this.workflowCache.get(workflowSlug);\n if (!workflowData) {\n console.error(`[StepWorker ${this.workerId}] Workflow ${workflowSlug} not found in cache`);\n return;\n }\n\n // Extract stepId from stepKey (handles nested steps with slashes)\n const stepId = extractStepId(stepKey);\n if (!stepId) {\n console.error(`[StepWorker ${this.workerId}] Invalid stepKey format: ${stepKey}`);\n return;\n }\n const step = workflowData.steps.find((s) => s.id === stepId);\n if (!step) {\n console.error(`[StepWorker ${this.workerId}] Step ${stepId} not found in workflow ${workflowSlug}`);\n return;\n }\n\n // Load step events to get current attempt number (using stepId)\n const events = await this.backend.loadEvents(workflowSlug, runId, { category: \"step\", stepId });\n const state = projectStepState(events, workflowSlug);\n const currentAttemptNumber = state.attemptNumber;\n\n const endTime = getMicrosecondTimestamp(); // Microseconds\n const duration = endTime - (state.startTime || startTime);\n\n // Prepare error object using centralized error serialization\n const stepError = serializeError(error);\n\n // SKIP DETECTION: Check if error is a Skip (don't retry, just mark as skipped)\n if (error instanceof Error && (error.name === \"Skip\" || error instanceof Skip)) {\n const skipError = error as Skip;\n\n await handleStepSkip(this.backend, workflowSlug, runId, stepId, skipError, duration, currentAttemptNumber);\n\n console.log(`[StepWorker ${this.workerId}] Skipped ${step.name}: ${skipError.reason || skipError.message}`);\n\n // If in unified mode, check for cascade skips\n if (this.options.mode === \"unified\") {\n const workflowData = this.workflowCache.get(workflowSlug);\n if (workflowData) {\n await cascadeSkip(this.backend, workflowSlug, runId, stepId, workflowData.steps, this.workerId);\n }\n }\n\n return; // Don't retry, don't mark as failed\n }\n\n // Check if we should retry\n const maxRetries = step.maxRetries ?? 0;\n if (currentAttemptNumber <= maxRetries) {\n // Not terminal - schedule retry atomically\n const retryDelayMs = step.retryDelayMs ?? 0;\n const nextRetryAt = getMicrosecondTimestamp() + retryDelayMs * MICROSECONDS_PER_MILLISECOND;\n\n // Use atomic method to ensure both failure and schedule events are written together\n await this.backend.saveStepFailedAndScheduleRetry(\n workflowSlug,\n runId,\n stepId,\n stepError,\n {\n duration,\n attemptNumber: currentAttemptNumber,\n nextRetryAt,\n failureReason: \"execution-error\",\n },\n {\n availableAt: nextRetryAt,\n nextAttemptNumber: currentAttemptNumber + 1,\n retryDelayMs,\n maxRetries,\n }\n );\n\n console.log(\n `[StepWorker ${this.workerId}] Scheduled retry for ${step.name} (attempt ${currentAttemptNumber + 1}/${maxRetries + 1})`\n );\n } else {\n // Terminal failure - retries exhausted\n await this.backend.saveStepFailed(workflowSlug, runId, stepId, stepError, {\n duration,\n attemptNumber: currentAttemptNumber,\n terminal: true,\n failureReason: \"exhausted-retries\",\n });\n\n console.log(`[StepWorker ${this.workerId}] Terminal failure for ${step.name} (retries exhausted)`);\n }\n }\n }\n\n /**\n * Set up signal handlers for graceful shutdown\n */\n private setupSignalHandlers(): void {\n const shutdown = async (signal: string) => {\n console.log(`[StepWorker ${this.workerId}] Received ${signal}, shutting down gracefully...`);\n await this.stop();\n process.exit(0);\n };\n\n process.on(\"SIGTERM\", () => shutdown(\"SIGTERM\"));\n process.on(\"SIGINT\", () => shutdown(\"SIGINT\"));\n }\n\n private heartbeatTimer?: Timer;\n}\n",
6
+ "import type { Backend } from \"@cascade-flow/backend-interface\";\nimport { projectStepState } from \"@cascade-flow/backend-interface\";\nimport { type LoadedStep } from \"@cascade-flow/runner\";\nimport { isOptional } from \"@cascade-flow/workflow\";\n\n/**\n * Check if all dependencies for a step are satisfied\n * Returns true if the step can be scheduled\n *\n * IMPORTANT: Both required AND optional dependencies must reach a terminal state\n * (completed or skipped) before a step can be scheduled. The distinction between\n * required and optional only affects CASCADE SKIP behavior:\n *\n * - Required dependency skips → dependent step is cascade skipped\n * - Optional dependency skips → dependent step executes with undefined value\n *\n * This means optional dependencies still BLOCK scheduling until they either complete\n * or skip. They only differ in how the dependent step handles the skipped state.\n *\n * @param step - The step to check dependencies for\n * @param backend - Backend interface for loading events\n * @param workflowSlug - Workflow identifier\n * @param runId - Run identifier\n * @returns true if all dependencies are in terminal state and satisfy execution requirements\n */\nexport async function checkDependenciesSatisfied(\n step: LoadedStep,\n backend: Backend,\n workflowSlug: string,\n runId: string\n): Promise<boolean> {\n for (const [depKey, dep] of Object.entries(step.dependencies) as [string, LoadedStep][]) {\n const depEvents = await backend.loadEvents(workflowSlug, runId, {\n category: \"step\",\n stepId: dep.id,\n });\n\n // If dependency has no events yet, we must wait regardless of optional status\n // Optional deps only skip blocking when they are in \"skipped\" terminal state\n if (depEvents.length === 0) {\n return false; // Dependency not ready - wait for it to complete or skip\n }\n\n const depState = projectStepState(depEvents as any, workflowSlug);\n const isOptionalDep = isOptional(step.dependencies[depKey]);\n\n // Check if dependency is in a terminal state we can accept\n if (depState.status === \"completed\") {\n continue; // Completed - always OK for both required and optional\n }\n\n if (depState.status === \"skipped\") {\n if (isOptionalDep) {\n continue; // Skipped optional dep - OK\n } else {\n return false; // Skipped required dep - blocks execution\n }\n }\n\n // Dependency is not in a terminal state (pending, scheduled, running, failed non-terminal)\n return false;\n }\n\n return true; // All dependencies satisfied\n}\n\n/**\n * Load outputs from all dependencies\n * Returns a map of dependency alias to output value\n *\n * This function should only be called after checkDependenciesSatisfied returns true,\n * ensuring all dependencies are in terminal state.\n *\n * Behavior by dependency state:\n * - Completed: Returns parsed JSON output\n * - Skipped + Optional: Returns undefined\n * - Skipped + Required: Throws error (should never happen - step should be cascade skipped)\n * - Any other state: Throws error (should never happen - checkDependenciesSatisfied should prevent scheduling)\n *\n * @param step - The step to load dependency outputs for\n * @param backend - Backend interface for loading events\n * @param workflowSlug - Workflow identifier\n * @param runId - Run identifier\n * @returns Map of dependency alias to output value (undefined for skipped optional deps)\n * @throws Error if dependency is not in a valid terminal state\n */\nexport async function loadDependencyOutputs(\n step: LoadedStep,\n backend: Backend,\n workflowSlug: string,\n runId: string\n): Promise<Record<string, any>> {\n const dependencyOutputs: Record<string, any> = {};\n\n for (const [depKey, depStep] of Object.entries(step.dependencies) as [string, LoadedStep][]) {\n const depEvents = await backend.loadEvents(workflowSlug, runId, {\n category: \"step\",\n stepId: depStep.id,\n });\n\n if (depEvents.length === 0) {\n // This should never happen if checkDependenciesSatisfied was called first\n // Both required and optional deps must have events (completed or skipped)\n throw new Error(`Dependency ${depStep.name} has no events - step was scheduled prematurely`);\n }\n\n const depState = projectStepState(depEvents as any, workflowSlug);\n const isOptionalDep = isOptional(step.dependencies[depKey]);\n\n // Optional deps can be skipped\n if (depState.status === \"skipped\" && isOptionalDep) {\n dependencyOutputs[depKey] = undefined;\n continue;\n }\n\n // At this point, dependency must be completed (not skipped optional which was handled above)\n // Note: output field is guaranteed to exist for completed steps (StepCompletedEvent requires it)\n if (depState.status !== \"completed\") {\n throw new Error(\n `Dependency '${depStep.name}' is not ready (status: ${depState.status}). ` +\n `This should not happen - checkDependenciesSatisfied should have prevented scheduling.`\n );\n }\n\n if (!depState.output) {\n throw new Error(`Dependency '${depStep.name}' has no output despite being completed`);\n }\n\n // Parse dependency output\n dependencyOutputs[depKey] = JSON.parse(depState.output);\n }\n\n return dependencyOutputs;\n}\n\n/**\n * Find all steps that depend on a given step\n * @param targetStepId - The stepId (unique identifier) to find dependents for\n * @param allSteps - All steps in the workflow\n * @param requiredOnly - If true, only return steps with required dependencies\n */\nexport function findDependentSteps(\n targetStepId: string,\n allSteps: LoadedStep[],\n requiredOnly: boolean = false\n): LoadedStep[] {\n return allSteps.filter((step) => {\n const deps = Object.entries(step.dependencies) as [string, LoadedStep][];\n return deps.some(([alias, dep]) => {\n const dependsOnTarget = dep.id === targetStepId;\n if (!dependsOnTarget) return false;\n\n if (requiredOnly) {\n const isOptionalDep = isOptional(step.dependencies[alias]);\n return !isOptionalDep; // Only include if it's a required dependency\n }\n\n return true; // Include all dependencies\n });\n });\n}\n",
7
7
  "import type { Backend } from \"@cascade-flow/backend-interface\";\nimport { getMicrosecondTimestamp, projectStepState } from \"@cascade-flow/backend-interface\";\nimport type { LoadedStep } from \"@cascade-flow/runner\";\nimport { findDependentSteps } from \"../execution/dependency-resolver.ts\";\n\n/**\n * Handle a step skip - emit StepSkipped event\n */\nexport async function handleStepSkip(\n backend: Backend,\n workflowSlug: string,\n runId: string,\n stepId: string,\n skipError: {\n reason?: string;\n message: string;\n metadata?: Record<string, unknown>;\n },\n duration: number,\n attemptNumber: number\n): Promise<void> {\n await backend.saveStepSkipped(workflowSlug, runId, stepId, {\n skipType: \"primary\",\n reason: skipError.reason || skipError.message.replace(\"Step skipped: \", \"\"),\n metadata: skipError.metadata,\n duration,\n attemptNumber,\n });\n}\n\n/**\n * Cascade skip to dependent steps that have the skipped step as a REQUIRED dependency\n * Recursively propagates skip to all dependent steps\n */\nexport async function cascadeSkip(\n backend: Backend,\n workflowSlug: string,\n runId: string,\n skippedStepId: string,\n allSteps: LoadedStep[],\n workerId: string\n): Promise<void> {\n // Find steps that depend on the skipped step as a REQUIRED dependency (using stepId)\n const dependentSteps = findDependentSteps(skippedStepId, allSteps, true);\n\n for (const dependentStep of dependentSteps) {\n // Check current state to avoid double-skipping (using stepId)\n const stepEvents = await backend.loadEvents(workflowSlug, runId, {\n category: \"step\",\n stepId: dependentStep.id,\n });\n const hasEvents = stepEvents.length > 0;\n\n // If step has no events yet or is not terminal (not completed/failed/skipped), cascade skip\n if (!hasEvents) {\n const now = getMicrosecondTimestamp(); // Microseconds\n\n // Emit StepStarted to mark as \"running\" briefly (for consistency) - using stepId\n await backend.saveStepStart(workflowSlug, runId, dependentStep.id, workerId, {\n dependencies: Object.keys(dependentStep.dependencies),\n timestamp: now,\n attemptNumber: 1,\n });\n\n // Immediately skip with cascade reason (using stepId)\n await backend.saveStepSkipped(workflowSlug, runId, dependentStep.id, {\n skipType: \"cascade\",\n reason: `Dependency '${skippedStepId}' was skipped`,\n duration: 0, // No actual execution time\n attemptNumber: 1,\n cascadedFrom: skippedStepId,\n });\n\n // Recursively cascade to further dependents (using stepId)\n await cascadeSkip(backend, workflowSlug, runId, dependentStep.id, allSteps, workerId);\n } else {\n const depState = projectStepState(stepEvents as any, workflowSlug);\n if (depState.status !== \"completed\" && depState.status !== \"failed\" && depState.status !== \"skipped\") {\n // Step is in progress or scheduled, still cascade skip (using stepId)\n await backend.saveStepSkipped(workflowSlug, runId, dependentStep.id, {\n skipType: \"cascade\",\n reason: `Dependency '${skippedStepId}' was skipped`,\n duration: getMicrosecondTimestamp() - (depState.startTime || getMicrosecondTimestamp()),\n attemptNumber: depState.attemptNumber,\n cascadedFrom: skippedStepId,\n });\n\n // Recursively cascade to further dependents (using stepId)\n await cascadeSkip(backend, workflowSlug, runId, dependentStep.id, allSteps, workerId);\n }\n }\n }\n}\n",
8
8
  "import type { Backend } from \"@cascade-flow/backend-interface\";\nimport { getMicrosecondTimestamp, projectStepState } from \"@cascade-flow/backend-interface\";\nimport type { LoadedStep } from \"@cascade-flow/runner\";\nimport { checkDependenciesSatisfied, findDependentSteps } from \"../execution/dependency-resolver.ts\";\n\n/**\n * Schedule a single step (emit StepScheduled event)\n */\nexport async function scheduleStep(\n backend: Backend,\n workflowSlug: string,\n runId: string,\n stepId: string,\n reason: \"initial\" | \"dependency-satisfied\" | \"retry\",\n attemptNumber: number,\n options?: {\n availableAt?: number;\n retryDelayMs?: number;\n }\n): Promise<void> {\n const now = getMicrosecondTimestamp();\n await backend.saveStepScheduled(workflowSlug, runId, stepId, {\n availableAt: options?.availableAt ?? now,\n reason,\n attemptNumber,\n retryDelayMs: options?.retryDelayMs,\n });\n}\n\n/**\n * Schedule initial steps (steps with no dependencies or all optional dependencies)\n */\nexport async function scheduleInitialSteps(\n backend: Backend,\n workflowSlug: string,\n runId: string,\n steps: LoadedStep[]\n): Promise<string[]> {\n const scheduledSteps: string[] = [];\n\n for (const step of steps) {\n // Check if step has no events yet (using stepId)\n const stepEvents = await backend.loadEvents(workflowSlug, runId, {\n category: \"step\",\n stepId: step.id,\n });\n\n if (stepEvents.length === 0) {\n // Check if dependencies are satisfied\n const canSchedule = await checkDependenciesSatisfied(step, backend, workflowSlug, runId);\n\n if (canSchedule) {\n await scheduleStep(\n backend,\n workflowSlug,\n runId,\n step.id,\n Object.keys(step.dependencies).length === 0 ? \"initial\" : \"dependency-satisfied\",\n 1\n );\n scheduledSteps.push(step.name);\n }\n }\n }\n\n return scheduledSteps;\n}\n\n/**\n * Schedule ready steps (pending steps whose dependencies are now satisfied)\n */\nexport async function scheduleReadySteps(\n backend: Backend,\n workflowSlug: string,\n runId: string,\n steps: LoadedStep[]\n): Promise<string[]> {\n const scheduledSteps: string[] = [];\n\n for (const step of steps) {\n const stepEvents = await backend.loadEvents(workflowSlug, runId, {\n category: \"step\",\n stepId: step.id,\n });\n\n // Skip if no events yet (handled by scheduleInitialSteps)\n if (stepEvents.length === 0) continue;\n\n const state = projectStepState(stepEvents as any, workflowSlug);\n\n // Only schedule if step is pending\n if (state.status === \"pending\") {\n const canSchedule = await checkDependenciesSatisfied(step, backend, workflowSlug, runId);\n\n if (canSchedule) {\n await scheduleStep(backend, workflowSlug, runId, step.id, \"dependency-satisfied\", 1);\n scheduledSteps.push(step.name);\n }\n }\n }\n\n return scheduledSteps;\n}\n\n/**\n * Schedule downstream steps (steps that depend on a newly completed step)\n */\nexport async function scheduleDownstreamSteps(\n backend: Backend,\n workflowSlug: string,\n runId: string,\n completedStepId: string,\n allSteps: LoadedStep[]\n): Promise<string[]> {\n const scheduledSteps: string[] = [];\n\n // Find steps that depend on the completed step (using stepId)\n const dependentSteps = findDependentSteps(completedStepId, allSteps, false);\n\n for (const dependentStep of dependentSteps) {\n // Check if all dependencies are completed\n const allDepsCompleted = await checkDependenciesSatisfied(dependentStep, backend, workflowSlug, runId);\n\n if (allDepsCompleted) {\n // Check current state to avoid double-scheduling (using stepId)\n const stepEvents = await backend.loadEvents(workflowSlug, runId, {\n category: \"step\",\n stepId: dependentStep.id,\n });\n\n // If step has no events yet, or is still pending, schedule it\n if (stepEvents.length === 0) {\n await scheduleStep(backend, workflowSlug, runId, dependentStep.id, \"dependency-satisfied\", 1);\n scheduledSteps.push(dependentStep.name);\n } else {\n const state = projectStepState(stepEvents as any, workflowSlug);\n if (state.status === \"pending\") {\n await scheduleStep(backend, workflowSlug, runId, dependentStep.id, \"dependency-satisfied\", 1);\n scheduledSteps.push(dependentStep.name);\n }\n }\n }\n }\n\n return scheduledSteps;\n}\n",
9
9
  "/**\n * Step key utilities\n *\n * A step key is a unique identifier in the format: `workflowSlug/runId/stepId`\n * where stepId may contain slashes for nested steps (e.g., \"slp/cognitive/extract-discrepancy\")\n */\n\n/**\n * Create a step key from its components\n *\n * @param workflowSlug - The workflow identifier\n * @param runId - The run identifier\n * @param stepId - The step identifier (may contain slashes for nested steps)\n * @returns The step key in format: `workflowSlug/runId/stepId`\n *\n * @example\n * createStepKey(\"pdpm\", \"run_123\", \"step-1\")\n * // => \"pdpm/run_123/step-1\"\n *\n * @example\n * createStepKey(\"pdpm\", \"run_123\", \"slp/cognitive/extract-discrepancy\")\n * // => \"pdpm/run_123/slp/cognitive/extract-discrepancy\"\n */\nexport function createStepKey(workflowSlug: string, runId: string, stepId: string): string {\n return `${workflowSlug}/${runId}/${stepId}`;\n}\n\n/**\n * Extract the stepId component from a step key\n *\n * Handles nested steps that contain slashes in their stepId.\n *\n * @param stepKey - The step key in format: `workflowSlug/runId/stepId`\n * @returns The stepId portion (everything after the first two slashes)\n *\n * @example\n * extractStepId(\"pdpm/run_123/step-1\")\n * // => \"step-1\"\n *\n * @example\n * extractStepId(\"pdpm/run_123/slp/cognitive/extract-discrepancy\")\n * // => \"slp/cognitive/extract-discrepancy\"\n */\nexport function extractStepId(stepKey: string): string {\n const parts = stepKey.split('/');\n return parts.slice(2).join('/');\n}\n\n/**\n * Extract the workflowSlug component from a step key\n *\n * @param stepKey - The step key in format: `workflowSlug/runId/stepId`\n * @returns The workflowSlug portion (first component)\n *\n * @example\n * extractWorkflowSlug(\"pdpm/run_123/step-1\")\n * // => \"pdpm\"\n */\nexport function extractWorkflowSlug(stepKey: string): string {\n return stepKey.split('/')[0]!;\n}\n\n/**\n * Extract the runId component from a step key\n *\n * @param stepKey - The step key in format: `workflowSlug/runId/stepId`\n * @returns The runId portion (second component)\n *\n * @example\n * extractRunId(\"pdpm/run_123/step-1\")\n * // => \"run_123\"\n */\nexport function extractRunId(stepKey: string): string {\n return stepKey.split('/')[1]!;\n}\n",
10
10
  "import type { Backend } from \"@cascade-flow/backend-interface\";\nimport { getMicrosecondTimestamp, projectStepState } from \"@cascade-flow/backend-interface\";\nimport type { ZodIssue, ZodSchema } from \"zod\";\nimport type { LoadedStep } from \"@cascade-flow/runner\";\nimport {\n calculateWorkflowDuration,\n getRunSubmittedEvent,\n getCurrentWorkflowAttemptNumber,\n} from \"../utils/event-helpers.ts\";\nimport type { WorkflowEvent } from \"../utils/event-helpers.ts\";\n\n/**\n * Handle workflow start - emit WorkflowStarted event\n */\nexport async function handleWorkflowStart(\n backend: Backend,\n workflowSlug: string,\n runId: string,\n metadata: {\n versionId: string;\n hasInputSchema: boolean;\n hasInput: boolean;\n },\n workflowEvents: WorkflowEvent[]\n): Promise<void> {\n const workflowAttemptNumber = getCurrentWorkflowAttemptNumber(workflowEvents);\n\n await backend.saveWorkflowStart(workflowSlug, runId, {\n versionId: metadata.versionId,\n workflowAttemptNumber,\n hasInputSchema: metadata.hasInputSchema,\n hasInput: metadata.hasInput,\n });\n}\n\n/**\n * Validate workflow input against schema\n * Returns validation result and emits WorkflowInputValidation event\n */\nexport async function validateWorkflowInput(\n backend: Backend,\n workflowSlug: string,\n runId: string,\n workflowInput: unknown,\n inputSchema: ZodSchema | undefined,\n workflowEvents: WorkflowEvent[]\n): Promise<{\n success: boolean;\n error?: { name: string; message: string };\n validationErrors?: Array<{ path: string; message: string }>;\n}> {\n const workflowAttemptNumber = getCurrentWorkflowAttemptNumber(workflowEvents);\n\n if (!inputSchema) {\n // No schema to validate against - if input provided, mark as success\n if (workflowInput !== undefined) {\n await backend.saveWorkflowInputValidation(workflowSlug, runId, {\n workflowAttemptNumber,\n hasSchema: false,\n success: true,\n });\n }\n return { success: true };\n }\n\n // Validate with schema\n const parseResult = inputSchema.safeParse(workflowInput ?? {});\n\n if (!parseResult.success) {\n const validationErrors = parseResult.error.issues.map((e: ZodIssue) => ({\n path: e.path.join(\".\"),\n message: e.message,\n }));\n\n const errorMessage = validationErrors\n .map((e: { path: string; message: string }) => ` ${e.path}: ${e.message}`)\n .join(\"\\n\");\n\n const error = {\n name: \"ValidationError\",\n message: `Invalid workflow input:\\n${errorMessage}`,\n };\n\n // Emit validation FAILURE event\n await backend.saveWorkflowInputValidation(workflowSlug, runId, {\n workflowAttemptNumber,\n hasSchema: true,\n success: false,\n error,\n validationErrors,\n });\n\n // Emit WorkflowFailed event\n const duration = calculateWorkflowDuration(workflowEvents);\n\n await backend.saveWorkflowFailed(\n workflowSlug,\n runId,\n error,\n {\n workflowAttemptNumber,\n duration,\n completedSteps: 0,\n },\n \"step-failed\" // Using existing failure reason\n );\n\n return { success: false, error, validationErrors };\n }\n\n // Validation succeeded - emit validation SUCCESS event\n await backend.saveWorkflowInputValidation(workflowSlug, runId, {\n workflowAttemptNumber,\n hasSchema: true,\n success: true,\n });\n\n return { success: true };\n}\n\n/**\n * Handle workflow completion - collect exported outputs and emit WorkflowCompleted event\n */\nexport async function handleWorkflowCompletion(\n backend: Backend,\n workflowSlug: string,\n runId: string,\n steps: LoadedStep[],\n workflowEvents: WorkflowEvent[]\n): Promise<void> {\n const workflowAttemptNumber = getCurrentWorkflowAttemptNumber(workflowEvents);\n const duration = calculateWorkflowDuration(workflowEvents);\n const now = getMicrosecondTimestamp();\n\n // Collect exported step outputs\n const output: Record<string, unknown> = {};\n for (const step of steps) {\n const stepEvents = await backend.loadEvents(workflowSlug, runId, {\n category: \"step\",\n stepId: step.id,\n });\n const state = projectStepState(stepEvents, workflowSlug);\n\n if (state.exportOutput && state.output) {\n output[step.name] = JSON.parse(state.output);\n }\n }\n\n await backend.saveWorkflowComplete(workflowSlug, runId, output, {\n workflowAttemptNumber,\n timestamp: now,\n duration,\n totalSteps: steps.length,\n });\n}\n\n/**\n * Handle workflow failure - count completed steps and emit WorkflowFailed event\n */\nexport async function handleWorkflowFailure(\n backend: Backend,\n workflowSlug: string,\n runId: string,\n steps: LoadedStep[],\n workflowEvents: WorkflowEvent[],\n failedStepName?: string\n): Promise<void> {\n const workflowAttemptNumber = getCurrentWorkflowAttemptNumber(workflowEvents);\n const duration = calculateWorkflowDuration(workflowEvents);\n\n // Count completed steps\n let completedCount = 0;\n for (const step of steps) {\n const stepEvents = await backend.loadEvents(workflowSlug, runId, {\n category: \"step\",\n stepId: step.id,\n });\n if (stepEvents.length > 0) {\n const state = projectStepState(stepEvents, workflowSlug);\n if (state.status === \"completed\") {\n completedCount++;\n }\n }\n }\n\n await backend.saveWorkflowFailed(\n workflowSlug,\n runId,\n {\n message: failedStepName ? `Step ${failedStepName} failed` : \"Workflow failed\",\n name: \"StepFailure\",\n },\n {\n workflowAttemptNumber,\n duration,\n completedSteps: completedCount,\n failedStep: failedStepName,\n },\n \"step-failed\"\n );\n}\n\n/**\n * Parse workflow input from RunSubmitted event\n */\nexport function parseWorkflowInput(workflowEvents: WorkflowEvent[]): unknown {\n const runSubmittedEvent = getRunSubmittedEvent(workflowEvents);\n if (runSubmittedEvent && runSubmittedEvent.input) {\n return JSON.parse(runSubmittedEvent.input);\n }\n return undefined;\n}\n",
11
11
  "import type { Backend, StepEvent, StepState, WorkflowEvent } from \"@cascade-flow/backend-interface\";\nimport { getMicrosecondTimestamp, projectStepState } from \"@cascade-flow/backend-interface\";\n\n// Re-export types for convenience\nexport type { WorkflowEvent, StepEvent, StepState };\n\n/**\n * Load step events and project to current state\n */\nexport async function loadStepState(\n backend: Backend,\n workflowSlug: string,\n runId: string,\n stepId: string\n): Promise<StepState> {\n const stepEvents = await backend.loadEvents(workflowSlug, runId, {\n category: \"step\",\n stepId,\n });\n\n return projectStepState(stepEvents, workflowSlug);\n}\n\n/**\n * Load all workflow events for a run\n */\nexport async function loadWorkflowEvents(\n backend: Backend,\n workflowSlug: string,\n runId: string\n): Promise<WorkflowEvent[]> {\n return backend.loadEvents(workflowSlug, runId, { category: \"workflow\" });\n}\n\n/**\n * Get the current workflow attempt number from events.\n * Returns 1 if no retry has occurred (initial attempt).\n * Returns the workflowAttemptNumber from the most recent WorkflowRetryStarted event.\n */\nexport function getCurrentWorkflowAttemptNumber(events: WorkflowEvent[]): number {\n const retryEvents = events.filter((e): e is Extract<WorkflowEvent, { type: \"WorkflowRetryStarted\" }> =>\n e.type === \"WorkflowRetryStarted\"\n );\n if (retryEvents.length === 0) return 1; // Initial attempt\n\n // Get the most recent retry (events are chronologically sorted)\n const mostRecentRetry = retryEvents[retryEvents.length - 1];\n if (!mostRecentRetry) return 1; // Extra safety check\n\n return mostRecentRetry.workflowAttemptNumber;\n}\n\n/**\n * Check if workflow is in a terminal state (completed, failed, or cancelled)\n * Only considers events from the current workflow attempt.\n */\nexport function isWorkflowTerminal(events: WorkflowEvent[]): boolean {\n const currentAttempt = getCurrentWorkflowAttemptNumber(events);\n return events.some((e) => {\n if (e.type === \"WorkflowCompleted\" || e.type === \"WorkflowFailed\" || e.type === \"WorkflowCancelled\") {\n return e.workflowAttemptNumber === currentAttempt;\n }\n return false;\n });\n}\n\n/**\n * Check specific terminal states\n * Only considers events from the current workflow attempt.\n */\nexport function getWorkflowTerminalState(events: WorkflowEvent[]): {\n hasCompleted: boolean;\n hasFailed: boolean;\n hasCancelled: boolean;\n} {\n const currentAttempt = getCurrentWorkflowAttemptNumber(events);\n\n return {\n hasCompleted: events.some((e) => e.type === \"WorkflowCompleted\" && e.workflowAttemptNumber === currentAttempt),\n hasFailed: events.some((e) => e.type === \"WorkflowFailed\" && e.workflowAttemptNumber === currentAttempt),\n hasCancelled: events.some((e) => e.type === \"WorkflowCancelled\" && e.workflowAttemptNumber === currentAttempt),\n };\n}\n\n/**\n * Calculate workflow duration from start event to now (in microseconds)\n * Uses the WorkflowStarted event from the current workflow attempt.\n */\nexport function calculateWorkflowDuration(events: WorkflowEvent[]): number {\n const currentAttempt = getCurrentWorkflowAttemptNumber(events);\n\n // Find WorkflowStarted event for current attempt\n const workflowStartEvent = events.find((e): e is Extract<WorkflowEvent, { type: \"WorkflowStarted\" }> =>\n e.type === \"WorkflowStarted\" && e.workflowAttemptNumber === currentAttempt\n );\n\n const startTime = workflowStartEvent ? workflowStartEvent.timestampUs : 0;\n const now = getMicrosecondTimestamp();\n return now - startTime;\n}\n\n/**\n * Check if workflow has been started\n * Only considers WorkflowStarted events from the current workflow attempt.\n */\nexport function hasWorkflowStarted(events: WorkflowEvent[]): boolean {\n const currentAttempt = getCurrentWorkflowAttemptNumber(events);\n return events.some((e) => e.type === \"WorkflowStarted\" && e.workflowAttemptNumber === currentAttempt);\n}\n\n/**\n * Check if workflow has been submitted\n */\nexport function hasWorkflowSubmitted(events: WorkflowEvent[]): boolean {\n return events.some((e) => e.type === \"RunSubmitted\");\n}\n\n/**\n * Check if workflow input has been validated\n * Only considers WorkflowInputValidation events from the current workflow attempt.\n */\nexport function hasWorkflowValidatedInput(events: WorkflowEvent[]): boolean {\n const currentAttempt = getCurrentWorkflowAttemptNumber(events);\n return events.some((e) => e.type === \"WorkflowInputValidation\" && e.workflowAttemptNumber === currentAttempt);\n}\n\n/**\n * Get the RunSubmitted event from workflow events\n */\nexport function getRunSubmittedEvent(events: WorkflowEvent[]): Extract<WorkflowEvent, { type: \"RunSubmitted\" }> | undefined {\n return events.find((e): e is Extract<WorkflowEvent, { type: \"RunSubmitted\" }> =>\n e.type === \"RunSubmitted\"\n );\n}\n\n/**\n * Get the WorkflowStarted event from workflow events\n * Returns the WorkflowStarted event from the current workflow attempt.\n */\nexport function getWorkflowStartedEvent(events: WorkflowEvent[]): Extract<WorkflowEvent, { type: \"WorkflowStarted\" }> | undefined {\n const currentAttempt = getCurrentWorkflowAttemptNumber(events);\n return events.find((e): e is Extract<WorkflowEvent, { type: \"WorkflowStarted\" }> =>\n e.type === \"WorkflowStarted\" && e.workflowAttemptNumber === currentAttempt\n );\n}\n\n/**\n * Get the WorkflowInputValidation event from workflow events\n * Returns the most recent WorkflowInputValidation event.\n *\n * Note: We return the most recent validation event regardless of attempt number because:\n * 1. Workflow input is immutable (stored once in RunSubmitted event)\n * 2. Input validation is idempotent - same input + schema = same result\n * 3. This prevents race conditions where executor claims steps before scheduler emits validation for new attempt\n * 4. Validation result from attempt 1 is valid for all subsequent retry attempts\n */\nexport function getWorkflowInputValidationEvent(events: WorkflowEvent[]): Extract<WorkflowEvent, { type: \"WorkflowInputValidation\" }> | undefined {\n // Get the most recent validation event (input doesn't change across attempts)\n const validationEvents = events.filter((e): e is Extract<WorkflowEvent, { type: \"WorkflowInputValidation\" }> =>\n e.type === \"WorkflowInputValidation\"\n );\n return validationEvents.length > 0 ? validationEvents[validationEvents.length - 1] : undefined;\n}\n"
12
12
  ],
13
- "mappings": "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",
14
- "debugId": "94F7F5AE1B4A4B8564756E2164756E21",
13
+ "mappings": "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",
14
+ "debugId": "6A12D877F6B3E36B64756E2164756E21",
15
15
  "names": []
16
16
  }
@@ -66,6 +66,12 @@ export declare class StepWorker {
66
66
  * Reclamation loop: Detects and reclaims stale steps from crashed workers
67
67
  */
68
68
  private reclamationLoop;
69
+ /**
70
+ * Load existing checkpoints for a step from events
71
+ *
72
+ * Returns a Map from checkpoint name to array of data (by sequence number)
73
+ */
74
+ private loadCheckpointsFromEvents;
69
75
  /**
70
76
  * Execute a single step
71
77
  */
@@ -1 +1 @@
1
- {"version":3,"file":"step-worker.d.ts","sourceRoot":"","sources":["../src/step-worker.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iCAAiC,CAAC;AAkB/D,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAWrE;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,WAAW,CAMJ;IACf,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,aAAa,CAA2F;gBAEpG,OAAO,CAAC,EAAE,OAAO,EAAE,OAAO,GAAE,iBAAsB;IAiC9D;;OAEG;IACH,QAAQ,IAAI,eAAe;IAI3B;;;;;;;OAOG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAiD5B;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAqB3B;;OAEG;YACW,aAAa;IAoB3B;;;OAGG;YACW,iBAAiB;IAsD/B;;OAEG;YACW,YAAY;IA4C1B;;OAEG;YACW,aAAa;IAqL3B;;OAEG;YACW,eAAe;IAqB7B;;OAEG;YACW,WAAW;IA+SzB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAW3B,OAAO,CAAC,cAAc,CAAC,CAAQ;CAChC"}
1
+ {"version":3,"file":"step-worker.d.ts","sourceRoot":"","sources":["../src/step-worker.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iCAAiC,CAAC;AAkB/D,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAWrE;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,WAAW,CAMJ;IACf,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,aAAa,CAA2F;gBAEpG,OAAO,CAAC,EAAE,OAAO,EAAE,OAAO,GAAE,iBAAsB;IAiC9D;;OAEG;IACH,QAAQ,IAAI,eAAe;IAI3B;;;;;;;OAOG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAiD5B;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAqB3B;;OAEG;YACW,aAAa;IAoB3B;;;OAGG;YACW,iBAAiB;IAsD/B;;OAEG;YACW,YAAY;IA4C1B;;OAEG;YACW,aAAa;IAqL3B;;OAEG;YACW,eAAe;IAqB7B;;;;OAIG;YACW,yBAAyB;IA2BvC;;OAEG;YACW,WAAW;IAyUzB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAW3B,OAAO,CAAC,cAAc,CAAC,CAAQ;CAChC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cascade-flow/worker",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -18,10 +18,10 @@
18
18
  "test": "bun test"
19
19
  },
20
20
  "dependencies": {
21
- "@cascade-flow/backend-interface": "0.2.2",
22
- "@cascade-flow/backend-filesystem": "0.2.4",
23
- "@cascade-flow/runner": "0.2.4",
24
- "@cascade-flow/workflow": "0.2.2"
21
+ "@cascade-flow/backend-interface": "0.2.4",
22
+ "@cascade-flow/backend-filesystem": "0.2.6",
23
+ "@cascade-flow/runner": "0.2.6",
24
+ "@cascade-flow/workflow": "0.2.6"
25
25
  },
26
26
  "devDependencies": {
27
27
  "@types/bun": "latest",