@cascade-flow/worker 0.2.6 → 0.2.8
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/dist/index.js +135 -16
- package/dist/index.js.map +6 -4
- package/dist/retry/index.d.ts +6 -0
- package/dist/retry/index.d.ts.map +1 -0
- package/dist/retry/policy-resolver.d.ts +82 -0
- package/dist/retry/policy-resolver.d.ts.map +1 -0
- package/dist/step-worker.d.ts.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -6,6 +6,77 @@ import { join } from "node:path";
|
|
|
6
6
|
import { discoverSteps, discoverWorkflows, executeStepInProcess, calculateWorkflowHash, getGitInfo } from "@cascade-flow/runner";
|
|
7
7
|
import { Skip } from "@cascade-flow/workflow";
|
|
8
8
|
|
|
9
|
+
// src/retry/policy-resolver.ts
|
|
10
|
+
function getCurrentPolicy(attemptNumber, policies) {
|
|
11
|
+
if (policies.length === 0) {
|
|
12
|
+
return { exhausted: true };
|
|
13
|
+
}
|
|
14
|
+
let accumulated = 0;
|
|
15
|
+
for (let i = 0;i < policies.length; i++) {
|
|
16
|
+
const policy = policies[i];
|
|
17
|
+
if (attemptNumber <= accumulated + policy.maxAttempts) {
|
|
18
|
+
return {
|
|
19
|
+
exhausted: false,
|
|
20
|
+
policy,
|
|
21
|
+
policyIndex: i,
|
|
22
|
+
attemptInPolicy: attemptNumber - accumulated
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
accumulated += policy.maxAttempts;
|
|
26
|
+
}
|
|
27
|
+
return { exhausted: true };
|
|
28
|
+
}
|
|
29
|
+
function computeDelay(backoff, attemptInPolicy) {
|
|
30
|
+
switch (backoff.type) {
|
|
31
|
+
case "constant":
|
|
32
|
+
return backoff.delayMs;
|
|
33
|
+
case "exponential": {
|
|
34
|
+
const multiplier = backoff.multiplier ?? 2;
|
|
35
|
+
const delay = backoff.initialDelayMs * Math.pow(multiplier, attemptInPolicy - 1);
|
|
36
|
+
return Math.min(delay, backoff.maxDelayMs);
|
|
37
|
+
}
|
|
38
|
+
case "linear": {
|
|
39
|
+
const delay = backoff.initialDelayMs + (attemptInPolicy - 1) * backoff.incrementMs;
|
|
40
|
+
return Math.min(delay, backoff.maxDelayMs);
|
|
41
|
+
}
|
|
42
|
+
default: {
|
|
43
|
+
const _exhaustive = backoff;
|
|
44
|
+
throw new Error(`Unknown backoff type: ${JSON.stringify(_exhaustive)}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function convertLegacyRetryConfig(maxRetries, retryDelayMs) {
|
|
49
|
+
if (!maxRetries || maxRetries <= 0) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
return [
|
|
53
|
+
{
|
|
54
|
+
maxAttempts: maxRetries + 1,
|
|
55
|
+
backoff: {
|
|
56
|
+
type: "constant",
|
|
57
|
+
delayMs: retryDelayMs ?? 0
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
];
|
|
61
|
+
}
|
|
62
|
+
function getTotalAttempts(policies) {
|
|
63
|
+
return policies.reduce((sum, p) => sum + p.maxAttempts, 0);
|
|
64
|
+
}
|
|
65
|
+
function resolveRetryPolicies(step) {
|
|
66
|
+
if (step.retry && step.retry.length > 0) {
|
|
67
|
+
return step.retry;
|
|
68
|
+
}
|
|
69
|
+
return convertLegacyRetryConfig(step.maxRetries, step.retryDelayMs);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// src/retry/index.ts
|
|
73
|
+
import {
|
|
74
|
+
RetryableError,
|
|
75
|
+
NonRetryableError,
|
|
76
|
+
isRetryableError,
|
|
77
|
+
isNonRetryableError
|
|
78
|
+
} from "@cascade-flow/workflow";
|
|
79
|
+
|
|
9
80
|
// src/execution/dependency-resolver.ts
|
|
10
81
|
import { projectStepState } from "@cascade-flow/backend-interface";
|
|
11
82
|
import { isOptional } from "@cascade-flow/workflow";
|
|
@@ -732,11 +803,28 @@ class StepWorker {
|
|
|
732
803
|
};
|
|
733
804
|
await this.backend.appendEvent(workflowSlug, runId, logEvent);
|
|
734
805
|
}, async (checkpoint) => {
|
|
806
|
+
let parentCheckpoint;
|
|
807
|
+
let label;
|
|
808
|
+
let cleanedData = checkpoint.data;
|
|
809
|
+
try {
|
|
810
|
+
const parsed = JSON.parse(checkpoint.data);
|
|
811
|
+
if (parsed?._parentCheckpoint) {
|
|
812
|
+
parentCheckpoint = parsed._parentCheckpoint;
|
|
813
|
+
delete parsed._parentCheckpoint;
|
|
814
|
+
}
|
|
815
|
+
if (parsed?._label) {
|
|
816
|
+
label = parsed._label;
|
|
817
|
+
delete parsed._label;
|
|
818
|
+
}
|
|
819
|
+
cleanedData = JSON.stringify(parsed);
|
|
820
|
+
} catch {}
|
|
735
821
|
await this.backend.saveStepCheckpoint(workflowSlug, runId, stepId, {
|
|
736
822
|
name: checkpoint.name,
|
|
737
823
|
sequenceNumber: checkpoint.sequenceNumber,
|
|
738
824
|
attemptNumber,
|
|
739
|
-
data:
|
|
825
|
+
data: cleanedData,
|
|
826
|
+
label,
|
|
827
|
+
parentCheckpoint
|
|
740
828
|
});
|
|
741
829
|
}, async (failure) => {
|
|
742
830
|
await this.backend.saveStepCheckpointFailed(workflowSlug, runId, stepId, {
|
|
@@ -828,30 +916,61 @@ class StepWorker {
|
|
|
828
916
|
}
|
|
829
917
|
return;
|
|
830
918
|
}
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
const retryDelayMs = step.retryDelayMs ?? 0;
|
|
834
|
-
const nextRetryAt = getMicrosecondTimestamp5() + retryDelayMs * MICROSECONDS_PER_MILLISECOND;
|
|
835
|
-
await this.backend.saveStepFailedAndScheduleRetry(workflowSlug, runId, stepId2, stepError, {
|
|
919
|
+
if (isNonRetryableError(error)) {
|
|
920
|
+
await this.backend.saveStepFailed(workflowSlug, runId, stepId2, stepError, {
|
|
836
921
|
duration,
|
|
837
922
|
attemptNumber: currentAttemptNumber,
|
|
838
|
-
|
|
923
|
+
terminal: true,
|
|
839
924
|
failureReason: "execution-error"
|
|
840
|
-
}, {
|
|
841
|
-
availableAt: nextRetryAt,
|
|
842
|
-
nextAttemptNumber: currentAttemptNumber + 1,
|
|
843
|
-
retryDelayMs,
|
|
844
|
-
maxRetries
|
|
845
925
|
});
|
|
846
|
-
console.log(`[StepWorker ${this.workerId}]
|
|
847
|
-
|
|
926
|
+
console.log(`[StepWorker ${this.workerId}] Terminal failure for ${step.name} (non-retryable error)`);
|
|
927
|
+
return;
|
|
928
|
+
}
|
|
929
|
+
const policies = resolveRetryPolicies(step);
|
|
930
|
+
if (!policies || policies.length === 0) {
|
|
931
|
+
await this.backend.saveStepFailed(workflowSlug, runId, stepId2, stepError, {
|
|
932
|
+
duration,
|
|
933
|
+
attemptNumber: currentAttemptNumber,
|
|
934
|
+
terminal: true,
|
|
935
|
+
failureReason: "execution-error"
|
|
936
|
+
});
|
|
937
|
+
console.log(`[StepWorker ${this.workerId}] Terminal failure for ${step.name} (no retry policy)`);
|
|
938
|
+
return;
|
|
939
|
+
}
|
|
940
|
+
const nextAttemptNumber = currentAttemptNumber + 1;
|
|
941
|
+
const policyResult = getCurrentPolicy(nextAttemptNumber, policies);
|
|
942
|
+
if (policyResult.exhausted) {
|
|
848
943
|
await this.backend.saveStepFailed(workflowSlug, runId, stepId2, stepError, {
|
|
849
944
|
duration,
|
|
850
945
|
attemptNumber: currentAttemptNumber,
|
|
851
946
|
terminal: true,
|
|
852
947
|
failureReason: "exhausted-retries"
|
|
853
948
|
});
|
|
854
|
-
|
|
949
|
+
const totalAttempts = getTotalAttempts(policies);
|
|
950
|
+
console.log(`[StepWorker ${this.workerId}] Terminal failure for ${step.name} (exhausted ${totalAttempts} attempts across ${policies.length} policies)`);
|
|
951
|
+
} else {
|
|
952
|
+
let retryDelayMs = computeDelay(policyResult.policy.backoff, policyResult.attemptInPolicy);
|
|
953
|
+
if (isRetryableError(error) && error.delayMs !== undefined) {
|
|
954
|
+
retryDelayMs = error.delayMs;
|
|
955
|
+
}
|
|
956
|
+
const nextRetryAt = getMicrosecondTimestamp5() + retryDelayMs * MICROSECONDS_PER_MILLISECOND;
|
|
957
|
+
await this.backend.saveStepFailedAndScheduleRetry(workflowSlug, runId, stepId2, stepError, {
|
|
958
|
+
duration,
|
|
959
|
+
attemptNumber: currentAttemptNumber,
|
|
960
|
+
nextRetryAt,
|
|
961
|
+
failureReason: "execution-error",
|
|
962
|
+
policyIndex: policyResult.policyIndex,
|
|
963
|
+
attemptInPolicy: policyResult.attemptInPolicy
|
|
964
|
+
}, {
|
|
965
|
+
availableAt: nextRetryAt,
|
|
966
|
+
nextAttemptNumber,
|
|
967
|
+
retryDelayMs,
|
|
968
|
+
totalPolicies: policies.length,
|
|
969
|
+
policyIndex: policyResult.policyIndex,
|
|
970
|
+
attemptInPolicy: policyResult.attemptInPolicy
|
|
971
|
+
});
|
|
972
|
+
const totalAttempts = getTotalAttempts(policies);
|
|
973
|
+
console.log(`[StepWorker ${this.workerId}] Scheduled retry for ${step.name} (attempt ${nextAttemptNumber}/${totalAttempts}, policy ${policyResult.policyIndex + 1}/${policies.length}, delay ${retryDelayMs}ms)`);
|
|
855
974
|
}
|
|
856
975
|
}
|
|
857
976
|
}
|
|
@@ -870,4 +989,4 @@ export {
|
|
|
870
989
|
StepWorker
|
|
871
990
|
};
|
|
872
991
|
|
|
873
|
-
//# debugId=
|
|
992
|
+
//# debugId=BD80EAAD1E5949DE64756E2164756E21
|
package/dist/index.js.map
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 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"],
|
|
3
|
+
"sources": ["../src/step-worker.ts", "../src/retry/policy-resolver.ts", "../src/retry/index.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, 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",
|
|
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 {\n getCurrentPolicy,\n computeDelay,\n resolveRetryPolicies,\n getTotalAttempts,\n isRetryableError,\n isNonRetryableError,\n} from \"./retry\";\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 // Extract metadata from data and strip from payload\n let parentCheckpoint:\n | { name: string; sequenceNumber: number }\n | undefined;\n let label: string | undefined;\n let cleanedData = checkpoint.data;\n try {\n const parsed = JSON.parse(checkpoint.data);\n if (parsed?._parentCheckpoint) {\n parentCheckpoint = parsed._parentCheckpoint;\n delete parsed._parentCheckpoint;\n }\n if (parsed?._label) {\n label = parsed._label;\n delete parsed._label;\n }\n // Re-serialize without metadata fields\n cleanedData = JSON.stringify(parsed);\n } catch {\n // Ignore parse errors - use original data\n }\n\n await this.backend.saveStepCheckpoint(workflowSlug, runId, stepId, {\n name: checkpoint.name,\n sequenceNumber: checkpoint.sequenceNumber,\n attemptNumber: attemptNumber!,\n data: cleanedData,\n label,\n parentCheckpoint,\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 for NonRetryableError - immediate terminal failure\n if (isNonRetryableError(error)) {\n await this.backend.saveStepFailed(workflowSlug, runId, stepId, stepError, {\n duration,\n attemptNumber: currentAttemptNumber,\n terminal: true,\n failureReason: \"execution-error\",\n });\n\n console.log(`[StepWorker ${this.workerId}] Terminal failure for ${step.name} (non-retryable error)`);\n return;\n }\n\n // Resolve retry policies (new format or legacy conversion)\n const policies = resolveRetryPolicies(step);\n\n // No retry policies configured - terminal failure\n if (!policies || policies.length === 0) {\n await this.backend.saveStepFailed(workflowSlug, runId, stepId, stepError, {\n duration,\n attemptNumber: currentAttemptNumber,\n terminal: true,\n failureReason: \"execution-error\",\n });\n\n console.log(`[StepWorker ${this.workerId}] Terminal failure for ${step.name} (no retry policy)`);\n return;\n }\n\n // Check if we should retry based on current attempt\n const nextAttemptNumber = currentAttemptNumber + 1;\n const policyResult = getCurrentPolicy(nextAttemptNumber, policies);\n\n if (policyResult.exhausted) {\n // Terminal failure - all retry policies 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 const totalAttempts = getTotalAttempts(policies);\n console.log(`[StepWorker ${this.workerId}] Terminal failure for ${step.name} (exhausted ${totalAttempts} attempts across ${policies.length} policies)`);\n } else {\n // Not terminal - schedule retry\n // Check if RetryableError provides a custom delay override\n let retryDelayMs = computeDelay(policyResult.policy.backoff, policyResult.attemptInPolicy);\n if (isRetryableError(error) && error.delayMs !== undefined) {\n retryDelayMs = error.delayMs;\n }\n\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 policyIndex: policyResult.policyIndex,\n attemptInPolicy: policyResult.attemptInPolicy,\n },\n {\n availableAt: nextRetryAt,\n nextAttemptNumber,\n retryDelayMs,\n totalPolicies: policies.length,\n policyIndex: policyResult.policyIndex,\n attemptInPolicy: policyResult.attemptInPolicy,\n }\n );\n\n const totalAttempts = getTotalAttempts(policies);\n console.log(\n `[StepWorker ${this.workerId}] Scheduled retry for ${step.name} (attempt ${nextAttemptNumber}/${totalAttempts}, policy ${policyResult.policyIndex + 1}/${policies.length}, delay ${retryDelayMs}ms)`\n );\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
|
+
"/**\n * Retry policy resolution and delay computation\n *\n * This module provides stateless functions for computing retry behavior\n * from attempt numbers and policy configurations.\n */\n\nimport type { RetryPolicy, BackoffConfig } from \"@cascade-flow/workflow\";\n\n/**\n * Result of policy resolution when a policy is found\n */\nexport type PolicyResolutionResult =\n | {\n exhausted: false;\n policy: RetryPolicy;\n policyIndex: number;\n attemptInPolicy: number; // 1-indexed within this policy\n }\n | {\n exhausted: true;\n };\n\n/**\n * Get the current policy for an attempt number\n *\n * @param attemptNumber - 1-indexed attempt number (the attempt we're about to make)\n * @param policies - Array of retry policies\n * @returns Policy resolution result\n *\n * @example\n * ```typescript\n * const policies = [\n * { maxAttempts: 10, backoff: { type: \"exponential\", ... } },\n * { maxAttempts: 10, backoff: { type: \"constant\", delayMs: 3600000 } },\n * ];\n *\n * getCurrentPolicy(1, policies) // → policy 0, attemptInPolicy 1\n * getCurrentPolicy(10, policies) // → policy 0, attemptInPolicy 10\n * getCurrentPolicy(11, policies) // → policy 1, attemptInPolicy 1\n * getCurrentPolicy(21, policies) // → exhausted\n * ```\n */\nexport function getCurrentPolicy(\n attemptNumber: number,\n policies: RetryPolicy[]\n): PolicyResolutionResult {\n if (policies.length === 0) {\n return { exhausted: true };\n }\n\n let accumulated = 0;\n\n for (let i = 0; i < policies.length; i++) {\n const policy = policies[i]!;\n if (attemptNumber <= accumulated + policy.maxAttempts) {\n return {\n exhausted: false,\n policy,\n policyIndex: i,\n attemptInPolicy: attemptNumber - accumulated,\n };\n }\n accumulated += policy.maxAttempts;\n }\n\n return { exhausted: true };\n}\n\n/**\n * Compute the delay for a given policy and attempt within that policy\n *\n * @param backoff - Backoff configuration\n * @param attemptInPolicy - 1-indexed attempt number within the policy\n * @returns Delay in milliseconds\n */\nexport function computeDelay(backoff: BackoffConfig, attemptInPolicy: number): number {\n switch (backoff.type) {\n case \"constant\":\n return backoff.delayMs;\n\n case \"exponential\": {\n const multiplier = backoff.multiplier ?? 2;\n // attemptInPolicy 1 → delay = initialDelayMs * multiplier^0 = initialDelayMs\n // attemptInPolicy 2 → delay = initialDelayMs * multiplier^1\n const delay = backoff.initialDelayMs * Math.pow(multiplier, attemptInPolicy - 1);\n return Math.min(delay, backoff.maxDelayMs);\n }\n\n case \"linear\": {\n // attemptInPolicy 1 → delay = initialDelayMs\n // attemptInPolicy 2 → delay = initialDelayMs + incrementMs\n const delay = backoff.initialDelayMs + (attemptInPolicy - 1) * backoff.incrementMs;\n return Math.min(delay, backoff.maxDelayMs);\n }\n\n default: {\n // Type guard for exhaustive check\n const _exhaustive: never = backoff;\n throw new Error(`Unknown backoff type: ${JSON.stringify(_exhaustive)}`);\n }\n }\n}\n\n/**\n * Convert legacy retry configuration to the new policy format\n *\n * @param maxRetries - Legacy maxRetries value (number of retries, not total attempts)\n * @param retryDelayMs - Legacy retryDelayMs value\n * @returns Array of retry policies, or undefined if no retry config\n *\n * @example\n * ```typescript\n * // maxRetries=3 means 4 total attempts (1 initial + 3 retries)\n * convertLegacyRetryConfig(3, 1000)\n * // → [{ maxAttempts: 4, backoff: { type: \"constant\", delayMs: 1000 } }]\n *\n * convertLegacyRetryConfig(0, 0)\n * // → undefined (no retries)\n * ```\n */\nexport function convertLegacyRetryConfig(\n maxRetries?: number,\n retryDelayMs?: number\n): RetryPolicy[] | undefined {\n // No retry if maxRetries is 0 or undefined\n if (!maxRetries || maxRetries <= 0) {\n return undefined;\n }\n\n // Legacy maxRetries means \"number of retries after initial attempt\"\n // So total attempts = maxRetries + 1\n return [\n {\n maxAttempts: maxRetries + 1,\n backoff: {\n type: \"constant\",\n delayMs: retryDelayMs ?? 0,\n },\n },\n ];\n}\n\n/**\n * Get the total number of attempts across all policies\n */\nexport function getTotalAttempts(policies: RetryPolicy[]): number {\n return policies.reduce((sum, p) => sum + p.maxAttempts, 0);\n}\n\n/**\n * Resolve effective retry policies from step configuration\n * Prefers new `retry` array over legacy `maxRetries`/`retryDelayMs`\n *\n * @param step - Step with retry configuration\n * @returns Resolved retry policies or undefined\n */\nexport function resolveRetryPolicies(step: {\n retry?: RetryPolicy[];\n maxRetries?: number;\n retryDelayMs?: number;\n}): RetryPolicy[] | undefined {\n // New format takes precedence\n if (step.retry && step.retry.length > 0) {\n return step.retry;\n }\n\n // Fall back to legacy format\n return convertLegacyRetryConfig(step.maxRetries, step.retryDelayMs);\n}\n",
|
|
7
|
+
"/**\n * Retry utilities for the worker package\n */\n\n// Policy resolution and delay computation\nexport {\n getCurrentPolicy,\n computeDelay,\n convertLegacyRetryConfig,\n getTotalAttempts,\n resolveRetryPolicies,\n type PolicyResolutionResult,\n} from \"./policy-resolver\";\n\n// Re-export error classes from workflow package for convenience\nexport {\n RetryableError,\n NonRetryableError,\n isRetryableError,\n isNonRetryableError,\n} from \"@cascade-flow/workflow\";\n",
|
|
6
8
|
"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
9
|
"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
10
|
"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",
|
|
@@ -10,7 +12,7 @@
|
|
|
10
12
|
"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
13
|
"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
14
|
],
|
|
13
|
-
"mappings": "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",
|
|
14
|
-
"debugId": "
|
|
15
|
+
"mappings": ";AAAA;AAEA,oCAAS,oGAA+E;AACxF;AACA;AACA;AACA;;;ACqCO,SAAS,gBAAgB,CAC9B,eACA,UACwB;AAAA,EACxB,IAAI,SAAS,WAAW,GAAG;AAAA,IACzB,OAAO,EAAE,WAAW,KAAK;AAAA,EAC3B;AAAA,EAEA,IAAI,cAAc;AAAA,EAElB,SAAS,IAAI,EAAG,IAAI,SAAS,QAAQ,KAAK;AAAA,IACxC,MAAM,SAAS,SAAS;AAAA,IACxB,IAAI,iBAAiB,cAAc,OAAO,aAAa;AAAA,MACrD,OAAO;AAAA,QACL,WAAW;AAAA,QACX;AAAA,QACA,aAAa;AAAA,QACb,iBAAiB,gBAAgB;AAAA,MACnC;AAAA,IACF;AAAA,IACA,eAAe,OAAO;AAAA,EACxB;AAAA,EAEA,OAAO,EAAE,WAAW,KAAK;AAAA;AAUpB,SAAS,YAAY,CAAC,SAAwB,iBAAiC;AAAA,EACpF,QAAQ,QAAQ;AAAA,SACT;AAAA,MACH,OAAO,QAAQ;AAAA,SAEZ,eAAe;AAAA,MAClB,MAAM,aAAa,QAAQ,cAAc;AAAA,MAGzC,MAAM,QAAQ,QAAQ,iBAAiB,KAAK,IAAI,YAAY,kBAAkB,CAAC;AAAA,MAC/E,OAAO,KAAK,IAAI,OAAO,QAAQ,UAAU;AAAA,IAC3C;AAAA,SAEK,UAAU;AAAA,MAGb,MAAM,QAAQ,QAAQ,kBAAkB,kBAAkB,KAAK,QAAQ;AAAA,MACvE,OAAO,KAAK,IAAI,OAAO,QAAQ,UAAU;AAAA,IAC3C;AAAA,aAES;AAAA,MAEP,MAAM,cAAqB;AAAA,MAC3B,MAAM,IAAI,MAAM,yBAAyB,KAAK,UAAU,WAAW,GAAG;AAAA,IACxE;AAAA;AAAA;AAqBG,SAAS,wBAAwB,CACtC,YACA,cAC2B;AAAA,EAE3B,IAAI,CAAC,cAAc,cAAc,GAAG;AAAA,IAClC;AAAA,EACF;AAAA,EAIA,OAAO;AAAA,IACL;AAAA,MACE,aAAa,aAAa;AAAA,MAC1B,SAAS;AAAA,QACP,MAAM;AAAA,QACN,SAAS,gBAAgB;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AAAA;AAMK,SAAS,gBAAgB,CAAC,UAAiC;AAAA,EAChE,OAAO,SAAS,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,aAAa,CAAC;AAAA;AAUpD,SAAS,oBAAoB,CAAC,MAIP;AAAA,EAE5B,IAAI,KAAK,SAAS,KAAK,MAAM,SAAS,GAAG;AAAA,IACvC,OAAO,KAAK;AAAA,EACd;AAAA,EAGA,OAAO,yBAAyB,KAAK,YAAY,KAAK,YAAY;AAAA;;;ACzJpE;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACdA;AAEA;AAsBA,eAAsB,0BAA0B,CAC9C,MACA,SACA,cACA,OACkB;AAAA,EAClB,YAAY,QAAQ,QAAQ,OAAO,QAAQ,KAAK,YAAY,GAA6B;AAAA,IACvF,MAAM,YAAY,MAAM,QAAQ,WAAW,cAAc,OAAO;AAAA,MAC9D,UAAU;AAAA,MACV,QAAQ,IAAI;AAAA,IACd,CAAC;AAAA,IAID,IAAI,UAAU,WAAW,GAAG;AAAA,MAC1B,OAAO;AAAA,IACT;AAAA,IAEA,MAAM,WAAW,iBAAiB,WAAkB,YAAY;AAAA,IAChE,MAAM,gBAAgB,WAAW,KAAK,aAAa,OAAO;AAAA,IAG1D,IAAI,SAAS,WAAW,aAAa;AAAA,MACnC;AAAA,IACF;AAAA,IAEA,IAAI,SAAS,WAAW,WAAW;AAAA,MACjC,IAAI,eAAe;AAAA,QACjB;AAAA,MACF,EAAO;AAAA,QACL,OAAO;AAAA;AAAA,IAEX;AAAA,IAGA,OAAO;AAAA,EACT;AAAA,EAEA,OAAO;AAAA;AAuBT,eAAsB,qBAAqB,CACzC,MACA,SACA,cACA,OAC8B;AAAA,EAC9B,MAAM,oBAAyC,CAAC;AAAA,EAEhD,YAAY,QAAQ,YAAY,OAAO,QAAQ,KAAK,YAAY,GAA6B;AAAA,IAC3F,MAAM,YAAY,MAAM,QAAQ,WAAW,cAAc,OAAO;AAAA,MAC9D,UAAU;AAAA,MACV,QAAQ,QAAQ;AAAA,IAClB,CAAC;AAAA,IAED,IAAI,UAAU,WAAW,GAAG;AAAA,MAG1B,MAAM,IAAI,MAAM,cAAc,QAAQ,qDAAqD;AAAA,IAC7F;AAAA,IAEA,MAAM,WAAW,iBAAiB,WAAkB,YAAY;AAAA,IAChE,MAAM,gBAAgB,WAAW,KAAK,aAAa,OAAO;AAAA,IAG1D,IAAI,SAAS,WAAW,aAAa,eAAe;AAAA,MAClD,kBAAkB,UAAU;AAAA,MAC5B;AAAA,IACF;AAAA,IAIA,IAAI,SAAS,WAAW,aAAa;AAAA,MACnC,MAAM,IAAI,MACR,eAAe,QAAQ,+BAA+B,SAAS,cAC/D,uFACF;AAAA,IACF;AAAA,IAEA,IAAI,CAAC,SAAS,QAAQ;AAAA,MACpB,MAAM,IAAI,MAAM,eAAe,QAAQ,6CAA6C;AAAA,IACtF;AAAA,IAGA,kBAAkB,UAAU,KAAK,MAAM,SAAS,MAAM;AAAA,EACxD;AAAA,EAEA,OAAO;AAAA;AASF,SAAS,kBAAkB,CAChC,cACA,UACA,eAAwB,OACV;AAAA,EACd,OAAO,SAAS,OAAO,CAAC,SAAS;AAAA,IAC/B,MAAM,OAAO,OAAO,QAAQ,KAAK,YAAY;AAAA,IAC7C,OAAO,KAAK,KAAK,EAAE,OAAO,SAAS;AAAA,MACjC,MAAM,kBAAkB,IAAI,OAAO;AAAA,MACnC,IAAI,CAAC;AAAA,QAAiB,OAAO;AAAA,MAE7B,IAAI,cAAc;AAAA,QAChB,MAAM,gBAAgB,WAAW,KAAK,aAAa,MAAM;AAAA,QACzD,OAAO,CAAC;AAAA,MACV;AAAA,MAEA,OAAO;AAAA,KACR;AAAA,GACF;AAAA;;;AC9JH,sDAAkC;AAOlC,eAAsB,cAAc,CAClC,SACA,cACA,OACA,QACA,WAKA,UACA,eACe;AAAA,EACf,MAAM,QAAQ,gBAAgB,cAAc,OAAO,QAAQ;AAAA,IACzD,UAAU;AAAA,IACV,QAAQ,UAAU,UAAU,UAAU,QAAQ,QAAQ,kBAAkB,EAAE;AAAA,IAC1E,UAAU,UAAU;AAAA,IACpB;AAAA,IACA;AAAA,EACF,CAAC;AAAA;AAOH,eAAsB,WAAW,CAC/B,SACA,cACA,OACA,eACA,UACA,UACe;AAAA,EAEf,MAAM,iBAAiB,mBAAmB,eAAe,UAAU,IAAI;AAAA,EAEvE,WAAW,iBAAiB,gBAAgB;AAAA,IAE1C,MAAM,aAAa,MAAM,QAAQ,WAAW,cAAc,OAAO;AAAA,MAC/D,UAAU;AAAA,MACV,QAAQ,cAAc;AAAA,IACxB,CAAC;AAAA,IACD,MAAM,YAAY,WAAW,SAAS;AAAA,IAGtC,IAAI,CAAC,WAAW;AAAA,MACd,MAAM,MAAM,wBAAwB;AAAA,MAGpC,MAAM,QAAQ,cAAc,cAAc,OAAO,cAAc,IAAI,UAAU;AAAA,QAC3E,cAAc,OAAO,KAAK,cAAc,YAAY;AAAA,QACpD,WAAW;AAAA,QACX,eAAe;AAAA,MACjB,CAAC;AAAA,MAGD,MAAM,QAAQ,gBAAgB,cAAc,OAAO,cAAc,IAAI;AAAA,QACnE,UAAU;AAAA,QACV,QAAQ,eAAe;AAAA,QACvB,UAAU;AAAA,QACV,eAAe;AAAA,QACf,cAAc;AAAA,MAChB,CAAC;AAAA,MAGD,MAAM,YAAY,SAAS,cAAc,OAAO,cAAc,IAAI,UAAU,QAAQ;AAAA,IACtF,EAAO;AAAA,MACL,MAAM,WAAW,kBAAiB,YAAmB,YAAY;AAAA,MACjE,IAAI,SAAS,WAAW,eAAe,SAAS,WAAW,YAAY,SAAS,WAAW,WAAW;AAAA,QAEpG,MAAM,QAAQ,gBAAgB,cAAc,OAAO,cAAc,IAAI;AAAA,UACnE,UAAU;AAAA,UACV,QAAQ,eAAe;AAAA,UACvB,UAAU,wBAAwB,KAAK,SAAS,aAAa,wBAAwB;AAAA,UACrF,eAAe,SAAS;AAAA,UACxB,cAAc;AAAA,QAChB,CAAC;AAAA,QAGD,MAAM,YAAY,SAAS,cAAc,OAAO,cAAc,IAAI,UAAU,QAAQ;AAAA,MACtF;AAAA;AAAA,EAEJ;AAAA;;;AC1FF,oCAAS,8CAAyB;AAOlC,eAAsB,YAAY,CAChC,SACA,cACA,OACA,QACA,QACA,eACA,SAIe;AAAA,EACf,MAAM,MAAM,yBAAwB;AAAA,EACpC,MAAM,QAAQ,kBAAkB,cAAc,OAAO,QAAQ;AAAA,IAC3D,aAAa,SAAS,eAAe;AAAA,IACrC;AAAA,IACA;AAAA,IACA,cAAc,SAAS;AAAA,EACzB,CAAC;AAAA;AAiFH,eAAsB,uBAAuB,CAC3C,SACA,cACA,OACA,iBACA,UACmB;AAAA,EACnB,MAAM,iBAA2B,CAAC;AAAA,EAGlC,MAAM,iBAAiB,mBAAmB,iBAAiB,UAAU,KAAK;AAAA,EAE1E,WAAW,iBAAiB,gBAAgB;AAAA,IAE1C,MAAM,mBAAmB,MAAM,2BAA2B,eAAe,SAAS,cAAc,KAAK;AAAA,IAErG,IAAI,kBAAkB;AAAA,MAEpB,MAAM,aAAa,MAAM,QAAQ,WAAW,cAAc,OAAO;AAAA,QAC/D,UAAU;AAAA,QACV,QAAQ,cAAc;AAAA,MACxB,CAAC;AAAA,MAGD,IAAI,WAAW,WAAW,GAAG;AAAA,QAC3B,MAAM,aAAa,SAAS,cAAc,OAAO,cAAc,IAAI,wBAAwB,CAAC;AAAA,QAC5F,eAAe,KAAK,cAAc,IAAI;AAAA,MACxC,EAAO;AAAA,QACL,MAAM,QAAQ,kBAAiB,YAAmB,YAAY;AAAA,QAC9D,IAAI,MAAM,WAAW,WAAW;AAAA,UAC9B,MAAM,aAAa,SAAS,cAAc,OAAO,cAAc,IAAI,wBAAwB,CAAC;AAAA,UAC5F,eAAe,KAAK,cAAc,IAAI;AAAA,QACxC;AAAA;AAAA,IAEJ;AAAA,EACF;AAAA,EAEA,OAAO;AAAA;;;ACzHF,SAAS,aAAa,CAAC,cAAsB,OAAe,QAAwB;AAAA,EACzF,OAAO,GAAG,gBAAgB,SAAS;AAAA;AAmB9B,SAAS,aAAa,CAAC,SAAyB;AAAA,EACrD,MAAM,QAAQ,QAAQ,MAAM,GAAG;AAAA,EAC/B,OAAO,MAAM,MAAM,CAAC,EAAE,KAAK,GAAG;AAAA;;;AC5ChC,oCAAS,8CAAyB;;;ACAlC,oCAAS,8CAAyB;AAyBlC,eAAsB,kBAAkB,CACtC,SACA,cACA,OAC0B;AAAA,EAC1B,OAAO,QAAQ,WAAW,cAAc,OAAO,EAAE,UAAU,WAAW,CAAC;AAAA;AAQlE,SAAS,+BAA+B,CAAC,QAAiC;AAAA,EAC/E,MAAM,cAAc,OAAO,OAAO,CAAC,MACjC,EAAE,SAAS,sBACb;AAAA,EACA,IAAI,YAAY,WAAW;AAAA,IAAG,OAAO;AAAA,EAGrC,MAAM,kBAAkB,YAAY,YAAY,SAAS;AAAA,EACzD,IAAI,CAAC;AAAA,IAAiB,OAAO;AAAA,EAE7B,OAAO,gBAAgB;AAAA;AAqBlB,SAAS,wBAAwB,CAAC,QAIvC;AAAA,EACA,MAAM,iBAAiB,gCAAgC,MAAM;AAAA,EAE7D,OAAO;AAAA,IACL,cAAc,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,uBAAuB,EAAE,0BAA0B,cAAc;AAAA,IAC7G,WAAW,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,oBAAoB,EAAE,0BAA0B,cAAc;AAAA,IACvG,cAAc,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,uBAAuB,EAAE,0BAA0B,cAAc;AAAA,EAC/G;AAAA;AAOK,SAAS,yBAAyB,CAAC,QAAiC;AAAA,EACzE,MAAM,iBAAiB,gCAAgC,MAAM;AAAA,EAG7D,MAAM,qBAAqB,OAAO,KAAK,CAAC,MACtC,EAAE,SAAS,qBAAqB,EAAE,0BAA0B,cAC9D;AAAA,EAEA,MAAM,YAAY,qBAAqB,mBAAmB,cAAc;AAAA,EACxE,MAAM,MAAM,yBAAwB;AAAA,EACpC,OAAO,MAAM;AAAA;AAOR,SAAS,kBAAkB,CAAC,QAAkC;AAAA,EACnE,MAAM,iBAAiB,gCAAgC,MAAM;AAAA,EAC7D,OAAO,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,qBAAqB,EAAE,0BAA0B,cAAc;AAAA;AAM/F,SAAS,oBAAoB,CAAC,QAAkC;AAAA,EACrE,OAAO,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,cAAc;AAAA;AAO9C,SAAS,yBAAyB,CAAC,QAAkC;AAAA,EAC1E,MAAM,iBAAiB,gCAAgC,MAAM;AAAA,EAC7D,OAAO,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,6BAA6B,EAAE,0BAA0B,cAAc;AAAA;AAMvG,SAAS,oBAAoB,CAAC,QAAuF;AAAA,EAC1H,OAAO,OAAO,KAAK,CAAC,MAClB,EAAE,SAAS,cACb;AAAA;AAwBK,SAAS,+BAA+B,CAAC,QAAkG;AAAA,EAEhJ,MAAM,mBAAmB,OAAO,OAAO,CAAC,MACtC,EAAE,SAAS,yBACb;AAAA,EACA,OAAO,iBAAiB,SAAS,IAAI,iBAAiB,iBAAiB,SAAS,KAAK;AAAA;;;ADnJvF,eAAsB,mBAAmB,CACvC,SACA,cACA,OACA,UAKA,gBACe;AAAA,EACf,MAAM,wBAAwB,gCAAgC,cAAc;AAAA,EAE5E,MAAM,QAAQ,kBAAkB,cAAc,OAAO;AAAA,IACnD,WAAW,SAAS;AAAA,IACpB;AAAA,IACA,gBAAgB,SAAS;AAAA,IACzB,UAAU,SAAS;AAAA,EACrB,CAAC;AAAA;AAOH,eAAsB,qBAAqB,CACzC,SACA,cACA,OACA,eACA,aACA,gBAKC;AAAA,EACD,MAAM,wBAAwB,gCAAgC,cAAc;AAAA,EAE5E,IAAI,CAAC,aAAa;AAAA,IAEhB,IAAI,kBAAkB,WAAW;AAAA,MAC/B,MAAM,QAAQ,4BAA4B,cAAc,OAAO;AAAA,QAC7D;AAAA,QACA,WAAW;AAAA,QACX,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAAA,IACA,OAAO,EAAE,SAAS,KAAK;AAAA,EACzB;AAAA,EAGA,MAAM,cAAc,YAAY,UAAU,iBAAiB,CAAC,CAAC;AAAA,EAE7D,IAAI,CAAC,YAAY,SAAS;AAAA,IACxB,MAAM,mBAAmB,YAAY,MAAM,OAAO,IAAI,CAAC,OAAiB;AAAA,MACtE,MAAM,EAAE,KAAK,KAAK,GAAG;AAAA,MACrB,SAAS,EAAE;AAAA,IACb,EAAE;AAAA,IAEF,MAAM,eAAe,iBAClB,IAAI,CAAC,MAAyC,KAAK,EAAE,SAAS,EAAE,SAAS,EACzE,KAAK;AAAA,CAAI;AAAA,IAEZ,MAAM,QAAQ;AAAA,MACZ,MAAM;AAAA,MACN,SAAS;AAAA,EAA4B;AAAA,IACvC;AAAA,IAGA,MAAM,QAAQ,4BAA4B,cAAc,OAAO;AAAA,MAC7D;AAAA,MACA,WAAW;AAAA,MACX,SAAS;AAAA,MACT;AAAA,MACA;AAAA,IACF,CAAC;AAAA,IAGD,MAAM,WAAW,0BAA0B,cAAc;AAAA,IAEzD,MAAM,QAAQ,mBACZ,cACA,OACA,OACA;AAAA,MACE;AAAA,MACA;AAAA,MACA,gBAAgB;AAAA,IAClB,GACA,aACF;AAAA,IAEA,OAAO,EAAE,SAAS,OAAO,OAAO,iBAAiB;AAAA,EACnD;AAAA,EAGA,MAAM,QAAQ,4BAA4B,cAAc,OAAO;AAAA,IAC7D;AAAA,IACA,WAAW;AAAA,IACX,SAAS;AAAA,EACX,CAAC;AAAA,EAED,OAAO,EAAE,SAAS,KAAK;AAAA;AAMzB,eAAsB,wBAAwB,CAC5C,SACA,cACA,OACA,OACA,gBACe;AAAA,EACf,MAAM,wBAAwB,gCAAgC,cAAc;AAAA,EAC5E,MAAM,WAAW,0BAA0B,cAAc;AAAA,EACzD,MAAM,MAAM,yBAAwB;AAAA,EAGpC,MAAM,SAAkC,CAAC;AAAA,EACzC,WAAW,QAAQ,OAAO;AAAA,IACxB,MAAM,aAAa,MAAM,QAAQ,WAAW,cAAc,OAAO;AAAA,MAC/D,UAAU;AAAA,MACV,QAAQ,KAAK;AAAA,IACf,CAAC;AAAA,IACD,MAAM,QAAQ,kBAAiB,YAAY,YAAY;AAAA,IAEvD,IAAI,MAAM,gBAAgB,MAAM,QAAQ;AAAA,MACtC,OAAO,KAAK,QAAQ,KAAK,MAAM,MAAM,MAAM;AAAA,IAC7C;AAAA,EACF;AAAA,EAEA,MAAM,QAAQ,qBAAqB,cAAc,OAAO,QAAQ;AAAA,IAC9D;AAAA,IACA,WAAW;AAAA,IACX;AAAA,IACA,YAAY,MAAM;AAAA,EACpB,CAAC;AAAA;AAMH,eAAsB,qBAAqB,CACzC,SACA,cACA,OACA,OACA,gBACA,gBACe;AAAA,EACf,MAAM,wBAAwB,gCAAgC,cAAc;AAAA,EAC5E,MAAM,WAAW,0BAA0B,cAAc;AAAA,EAGzD,IAAI,iBAAiB;AAAA,EACrB,WAAW,QAAQ,OAAO;AAAA,IACxB,MAAM,aAAa,MAAM,QAAQ,WAAW,cAAc,OAAO;AAAA,MAC/D,UAAU;AAAA,MACV,QAAQ,KAAK;AAAA,IACf,CAAC;AAAA,IACD,IAAI,WAAW,SAAS,GAAG;AAAA,MACzB,MAAM,QAAQ,kBAAiB,YAAY,YAAY;AAAA,MACvD,IAAI,MAAM,WAAW,aAAa;AAAA,QAChC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,QAAQ,mBACZ,cACA,OACA;AAAA,IACE,SAAS,iBAAiB,QAAQ,0BAA0B;AAAA,IAC5D,MAAM;AAAA,EACR,GACA;AAAA,IACE;AAAA,IACA;AAAA,IACA,gBAAgB;AAAA,IAChB,YAAY;AAAA,EACd,GACA,aACF;AAAA;AAMK,SAAS,kBAAkB,CAAC,gBAA0C;AAAA,EAC3E,MAAM,oBAAoB,qBAAqB,cAAc;AAAA,EAC7D,IAAI,qBAAqB,kBAAkB,OAAO;AAAA,IAChD,OAAO,KAAK,MAAM,kBAAkB,KAAK;AAAA,EAC3C;AAAA,EACA;AAAA;;;AP1JK,MAAM,WAAW;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAmB;AAAA,EACnB,cAMH,IAAI;AAAA,EACD;AAAA,EACA,gBAA8F,IAAI;AAAA,EAE1G,WAAW,CAAC,SAAmB,UAA6B,CAAC,GAAG;AAAA,IAE9D,KAAK,WAAW,QAAQ,YAAY,eAAe,SAAS,KAAK,QAAQ,OAAO,yBAAwB;AAAA,IAGxG,KAAK,UAAU,WAAW,IAAI,kBAAkB,QAAQ,WAAW,SAAS;AAAA,IAG5E,KAAK,UAAU;AAAA,MACb,UAAU,KAAK;AAAA,MACf,MAAM,QAAQ,QAAQ;AAAA,MACtB,aAAa,QAAQ,eAAe;AAAA,MACpC,cAAc,QAAQ,gBAAgB;AAAA,MACtC,mBAAmB,QAAQ,qBAAqB;AAAA,MAChD,gBAAgB,QAAQ,kBAAkB;AAAA,MAC1C,oBAAoB,QAAQ,sBAAsB;AAAA,MAClD,mBAAmB,QAAQ,qBAAqB;AAAA,MAChD,iBAAiB,QAAQ,mBAAmB;AAAA,MAC5C,cAAc,QAAQ,gBAAgB;AAAA,MACtC,SAAS,QAAQ,WAAW;AAAA,IAC9B;AAAA,IAEA,KAAK,QAAQ;AAAA,MACX,UAAU,KAAK;AAAA,MACf,MAAM,KAAK,QAAQ;AAAA,MACnB,WAAW,yBAAwB;AAAA,MACnC,qBAAqB;AAAA,MACrB,kBAAkB;AAAA,MAClB,aAAa;AAAA,MACb,gBAAgB;AAAA,IAClB;AAAA;AAAA,EAMF,QAAQ,GAAoB;AAAA,IAC1B,OAAO,KAAK,KAAK,MAAM;AAAA;AAAA,OAWnB,MAAK,GAAkB;AAAA,IAC3B,IAAI,KAAK,SAAS;AAAA,MAChB,MAAM,IAAI,MAAM,2BAA2B;AAAA,IAC7C;AAAA,IAEA,KAAK,UAAU;AAAA,IACf,QAAQ,IAAI,eAAe,KAAK,yBAAyB,KAAK,QAAQ,cAAc;AAAA,IAGpF,KAAK,oBAAoB;AAAA,IAGzB,QAAQ,IAAI,eAAe,KAAK,oCAAoC,KAAK,QAAQ,iBAAiB;AAAA,IAClG,MAAM,KAAK,cAAc;AAAA,IAGzB,QAAQ,IAAI,eAAe,KAAK,iDAAiD;AAAA,IACjF,MAAM,KAAK,kBAAkB;AAAA,IAG7B,MAAM,QAAyB,CAAC;AAAA,IAEhC,IAAI,KAAK,QAAQ,SAAS,aAAa,KAAK,QAAQ,SAAS,YAAY;AAAA,MAEvE,MAAM,KAAK,KAAK,aAAa,CAAC;AAAA,MAC9B,QAAQ,IAAI,eAAe,KAAK,iDAAiD,KAAK,QAAQ,cAAc;AAAA,IAC9G;AAAA,IAEA,IAAI,KAAK,QAAQ,SAAS,aAAa,KAAK,QAAQ,SAAS,aAAa;AAAA,MAExE,MAAM,KAAK,KAAK,cAAc,CAAC;AAAA,MAC/B,QAAQ,IAAI,eAAe,KAAK,+CAA+C,KAAK,QAAQ,sBAAsB;AAAA,MAGlH,MAAM,KAAK,KAAK,gBAAgB,CAAC;AAAA,MACjC,QAAQ,IAAI,eAAe,KAAK,kDAAkD,KAAK,QAAQ,mBAAmB;AAAA,IACpH;AAAA,IAEA,QAAQ,IAAI,eAAe,KAAK,gCAAgC;AAAA,IAGhE,IAAI;AAAA,MACF,MAAM,QAAQ,IAAI,KAAK;AAAA,cACvB;AAAA,MACA,cAAc,KAAK,cAAqB;AAAA,MACxC,QAAQ,IAAI,eAAe,KAAK,mBAAmB;AAAA;AAAA;AAAA,OAQjD,KAAI,GAAkB;AAAA,IAC1B,IAAI,CAAC,KAAK,SAAS;AAAA,MACjB;AAAA,IACF;AAAA,IAEA,QAAQ,IAAI,eAAe,KAAK,0BAA0B,KAAK,YAAY,oBAAoB;AAAA,IAC/F,KAAK,UAAU;AAAA,IAGf,MAAM,gBAAgB,KAAK,IAAI;AAAA,IAC/B,OAAO,KAAK,YAAY,OAAO,KAAK,KAAK,IAAI,IAAI,gBAAgB,KAAK,QAAQ,iBAAiB;AAAA,MAC7F,MAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,GAAG,CAAC;AAAA,IACzD;AAAA,IAEA,IAAI,KAAK,YAAY,OAAO,GAAG;AAAA,MAC7B,QAAQ,KAAK,eAAe,KAAK,kCAAkC,KAAK,YAAY,mBAAmB;AAAA,IACzG;AAAA,IAEA,QAAQ,IAAI,eAAe,KAAK,mBAAmB;AAAA;AAAA,OAMvC,cAAa,GAAkB;AAAA,IAC3C,IAAI;AAAA,MACF,MAAM,YAAY,MAAM,kBAAkB,KAAK,QAAQ,YAAY;AAAA,MAEnE,WAAW,YAAY,WAAW;AAAA,QAChC,MAAM,QAAQ,MAAM,cAAc,SAAS,QAAQ;AAAA,QACnD,KAAK,cAAc,IAAI,SAAS,MAAM;AAAA,UACpC,UAAU;AAAA,UACV;AAAA,UACA,aAAa,SAAS;AAAA,QACxB,CAAC;AAAA,MACH;AAAA,MAEA,QAAQ,IAAI,eAAe,KAAK,oBAAoB,UAAU,kBAAkB;AAAA,MAChF,OAAO,OAAO;AAAA,MACd,QAAQ,MAAM,eAAe,KAAK,uCAAuC,KAAK;AAAA,MAC9E,MAAM;AAAA;AAAA;AAAA,OAQI,kBAAiB,GAAkB;AAAA,IAC/C,IAAI;AAAA,MACF,YAAY,QAAQ,UAAU,OAAO,kBAAkB,KAAK,eAAe;AAAA,QAEzE,IAAI,kBAAkB;AAAA,QACtB,IAAI,aAAa;AAAA,UACf,IAAI;AAAA,YACF,kBAAkB,uBAAuB,WAAW;AAAA,YACpD,OAAO,OAAO;AAAA,YACd,QAAQ,KACN,eAAe,KAAK,mDAAmD,SAAS,OAClF;AAAA;AAAA,QAEJ;AAAA,QAGA,MAAM,kBAAkB,MAAM,IAAI,CAAC,UAAU;AAAA,UAC3C,IAAI,KAAK;AAAA,UACT,MAAM,KAAK;AAAA,UACX,cAAc,OAAO,OAAO,KAAK,YAAY,EAAE,IAAI,SAAO,IAAI,EAAE;AAAA,UAChE,cAAc,KAAK,gBAAgB;AAAA,QACrC,EAAE;AAAA,QAGF,MAAM,KAAK,QAAQ,iBAAiB;AAAA,UAClC;AAAA,UACA,MAAM,SAAS;AAAA,UACf,UAAU,SAAS;AAAA,UACnB;AAAA,UACA,OAAO;AAAA,QACT,CAAC;AAAA,QAGD,MAAM,YAAY,MAAM,sBAAsB,QAAQ;AAAA,QACtD,MAAM,MAAM,MAAM,WAAW,SAAS,GAAG;AAAA,QACzC,MAAM,eAAe,MAAM,IAAI,CAAC,MAAM,EAAE,EAAE;AAAA,QAE1C,MAAM,KAAK,QAAQ,sBAAsB;AAAA,UACvC,cAAc;AAAA,UACd;AAAA,UACA,WAAW,yBAAwB;AAAA,UACnC;AAAA,UACA,YAAY,MAAM;AAAA,UAClB;AAAA,QACF,CAAC;AAAA,MACH;AAAA,MAEA,QAAQ,IAAI,eAAe,KAAK,wBAAwB,KAAK,cAAc,gBAAgB;AAAA,MAC3F,OAAO,OAAO;AAAA,MACd,QAAQ,MAAM,eAAe,KAAK,2CAA2C,KAAK;AAAA,MAClF,MAAM;AAAA;AAAA;AAAA,OAOI,aAAY,GAAkB;AAAA,IAC1C,OAAO,KAAK,SAAS;AAAA,MACnB,IAAI;AAAA,QAEF,IAAI,KAAK,YAAY,QAAQ,KAAK,QAAQ,aAAa;AAAA,UACrD,MAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,KAAK,QAAQ,YAAY,CAAC;AAAA,UAC7E;AAAA,QACF;AAAA,QAGA,MAAM,QAAQ,KAAK,QAAQ,cAAc,KAAK,YAAY;AAAA,QAC1D,MAAM,iBAAiB,MAAM,KAAK,QAAQ,mBAAmB,EAAE,MAAM,CAAC;AAAA,QAEtE,IAAI,eAAe,WAAW,GAAG;AAAA,UAE/B,MAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,KAAK,QAAQ,YAAY,CAAC;AAAA,UAC7E;AAAA,QACF;AAAA,QAGA,aAAa,cAAc,OAAO,YAAY,gBAAgB;AAAA,UAC5D,IAAI,KAAK,YAAY,QAAQ,KAAK,QAAQ,aAAa;AAAA,YACrD;AAAA,UACF;AAAA,UAGA,MAAM,cAAc,MAAM,KAAK,QAAQ,gBAAgB,cAAc,OAAO,MAAM;AAAA,UAElF,IAAI,CAAC,aAAa;AAAA,YAChB;AAAA,UACF;AAAA,UAGA,KAAK,YAAY,cAAc,OAAO,MAAM,EAAE,MAAM,CAAC,QAAQ;AAAA,YAC3D,QAAQ,MAAM,eAAe,KAAK,6BAA6B,cAAc,cAAc,OAAO,MAAM,MAAM,GAAG;AAAA,WAClH;AAAA,QACH;AAAA,QACA,OAAO,OAAO;AAAA,QACd,QAAQ,MAAM,eAAe,KAAK,qCAAqC,KAAK;AAAA,QAC5E,MAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,KAAK,QAAQ,YAAY,CAAC;AAAA;AAAA,IAEjF;AAAA;AAAA,OAMY,cAAa,GAAkB;AAAA,IAC3C,OAAO,KAAK,SAAS;AAAA,MACnB,IAAI;AAAA,QAEF,MAAM,kBAAkB,MAAM,KAAK,QAAQ,oBAAoB;AAAA,QAE/D,WAAW,gBAAgB,iBAAiB;AAAA,UAE1C,MAAM,eAAe,KAAK,cAAc,IAAI,YAAY;AAAA,UACxD,IAAI,CAAC,cAAc;AAAA,YACjB,QAAQ,KAAK,eAAe,KAAK,sBAAsB,qCAAqC;AAAA,YAC5F;AAAA,UACF;AAAA,UAGA,IAAI,SAAmB,CAAC;AAAA,UACxB,IAAI;AAAA,YACF,SAAS,MAAM,KAAK,QAAQ,WAAW,YAAY;AAAA,YACnD,MAAM;AAAA,YAEN;AAAA;AAAA,UAGF,WAAW,SAAS,QAAQ;AAAA,YAC1B,IAAI;AAAA,cAEF,MAAM,iBAAiB,MAAM,mBAAmB,KAAK,SAAS,cAAc,KAAK;AAAA,cACjF,IAAI,eAAe,WAAW;AAAA,gBAAG;AAAA,cAGjC,QAAQ,cAAc,WAAW,iBAAiB,yBAAyB,cAAc;AAAA,cAEzF,IAAI,gBAAgB,aAAa,cAAc;AAAA,gBAC7C;AAAA,cACF;AAAA,cAGA,MAAM,eAAe,qBAAqB,cAAc;AAAA,cACxD,MAAM,aAAa,mBAAmB,cAAc;AAAA,cAEpD,IAAI,CAAC,cAAc;AAAA,gBACjB;AAAA,cACF;AAAA,cAGA,IAAI,CAAC,YAAY;AAAA,gBACf,MAAM,oBAAoB,qBAAqB,cAAc;AAAA,gBAC7D,IAAI,CAAC,mBAAmB;AAAA,kBACtB,MAAM,IAAI,MAAM,mCAAmC,gBAAgB,OAAO;AAAA,gBAC5E;AAAA,gBAEA,MAAM,oBAAoB,KAAK,SAAS,cAAc,OAAO;AAAA,kBAC3D,WAAW,kBAAkB;AAAA,kBAC7B,gBAAgB,aAAa,gBAAgB;AAAA,kBAC7C,UAAU,CAAC,EAAE,qBAAqB,kBAAkB,UAAU;AAAA,gBAChE,GAAG,cAAc;AAAA,gBAEjB,QAAQ,IAAI,eAAe,KAAK,8BAA8B,gBAAgB,OAAO;AAAA,cACvF;AAAA,cAGA,MAAM,oBAAoB,0BAA0B,cAAc;AAAA,cAElE,IAAI,CAAC,mBAAmB;AAAA,gBACtB,MAAM,gBAAgB,mBAAmB,cAAc;AAAA,gBACvD,MAAM,mBAAmB,MAAM,sBAC7B,KAAK,SACL,cACA,OACA,eACA,aAAa,aACb,cACF;AAAA,gBAEA,IAAI,CAAC,iBAAiB,SAAS;AAAA,kBAC7B,QAAQ,IACN,eAAe,KAAK,sBAAsB,gBAAgB,iCAC5D;AAAA,kBACA;AAAA,gBACF;AAAA,cACF;AAAA,cAGA,IAAI,oBAAoB;AAAA,cACxB,IAAI,gBAAgB;AAAA,cACpB,IAAI;AAAA,cAGJ,MAAM,gBAAgB,MAAM,KAAK,QAAQ,4BAA4B,cAAc,KAAK;AAAA,cAGxF,WAAW,QAAQ,aAAa,OAAO;AAAA,gBAErC,MAAM,aAAa,cAAc,IAAI,KAAK,EAAE,KAAK,CAAC;AAAA,gBAGlD,IAAI,WAAW,WAAW,GAAG;AAAA,kBAC3B,oBAAoB;AAAA,kBAGpB,MAAM,cAAc,MAAM,2BAA2B,MAAM,KAAK,SAAS,cAAc,KAAK;AAAA,kBAG5F,IAAI,aAAa;AAAA,oBACf,MAAM,aACJ,KAAK,SACL,cACA,OACA,KAAK,IACL,OAAO,KAAK,KAAK,YAAY,EAAE,WAAW,IAAI,YAAY,wBAC1D,CACF;AAAA,oBAEA,QAAQ,IAAI,eAAe,KAAK,uBAAuB,KAAK,WAAW,gBAAgB,OAAO;AAAA,kBAChG;AAAA,gBACF,EAAO;AAAA,kBAEL,MAAM,QAAQ,kBAAiB,YAAY,YAAY;AAAA,kBAEvD,IAAI,MAAM,WAAW,WAAW;AAAA,oBAC9B,oBAAoB;AAAA,oBAGpB,MAAM,cAAc,MAAM,2BAA2B,MAAM,KAAK,SAAS,cAAc,KAAK;AAAA,oBAE5F,IAAI,aAAa;AAAA,sBACf,MAAM,aAAa,KAAK,SAAS,cAAc,OAAO,KAAK,IAAI,wBAAwB,CAAC;AAAA,sBAExF,QAAQ,IACN,eAAe,KAAK,oCAAoC,KAAK,WAAW,gBAAgB,OAC1F;AAAA,oBACF;AAAA,kBACF,EAAO,SAAI,MAAM,WAAW,YAAY,MAAM,UAAU;AAAA,oBACtD,gBAAgB;AAAA,oBAChB,iBAAiB,KAAK;AAAA,oBACtB,oBAAoB;AAAA,kBACtB,EAAO,SAAI,MAAM,WAAW,eAAe,MAAM,WAAW,WAAW;AAAA,oBACrE,oBAAoB;AAAA,kBACtB;AAAA;AAAA,cAEJ;AAAA,cAGA,IAAI,mBAAmB;AAAA,gBACrB,MAAM,yBACJ,KAAK,SACL,cACA,OACA,aAAa,OACb,cACF;AAAA,gBAEA,QAAQ,IAAI,eAAe,KAAK,sBAAsB,gBAAgB,iBAAiB;AAAA,cACzF,EAAO,SAAI,eAAe;AAAA,gBACxB,MAAM,sBACJ,KAAK,SACL,cACA,OACA,aAAa,OACb,gBACA,cACF;AAAA,gBAEA,QAAQ,IACN,eAAe,KAAK,sBAAsB,gBAAgB,uBAAuB,iBACnF;AAAA,cACF;AAAA,cACA,OAAO,OAAO;AAAA,cACd,QAAQ,MAAM,eAAe,KAAK,kCAAkC,UAAU,KAAK;AAAA;AAAA,UAEvF;AAAA,QACF;AAAA,QAEA,MAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,KAAK,QAAQ,iBAAiB,CAAC;AAAA,QAClF,OAAO,OAAO;AAAA,QACd,QAAQ,MAAM,eAAe,KAAK,sCAAsC,KAAK;AAAA,QAC7E,MAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,KAAK,QAAQ,iBAAiB,CAAC;AAAA;AAAA,IAEtF;AAAA;AAAA,OAMY,gBAAe,GAAkB;AAAA,IAC7C,OAAO,KAAK,SAAS;AAAA,MACnB,IAAI;AAAA,QACF,MAAM,YAAY,MAAM,KAAK,QAAQ,kBACnC,KAAK,QAAQ,iBAAiB,MAC9B,KAAK,QACP;AAAA,QAEA,IAAI,UAAU,SAAS,GAAG;AAAA,UACxB,QAAQ,IAAI,eAAe,KAAK,uBAAuB,UAAU,oBAAoB;AAAA,UACrF,KAAK,MAAM,kBAAkB,UAAU;AAAA,QACzC;AAAA,QAEA,MAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,KAAK,QAAQ,kBAAkB,CAAC;AAAA,QACnF,OAAO,OAAO;AAAA,QACd,QAAQ,MAAM,eAAe,KAAK,wCAAwC,KAAK;AAAA,QAC/E,MAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,KAAK,QAAQ,kBAAkB,CAAC;AAAA;AAAA,IAEvF;AAAA;AAAA,OAQY,0BAAyB,CACrC,cACA,OACA,QACgC;AAAA,IAChC,MAAM,SAAS,MAAM,KAAK,QAAQ,WAAW,cAAc,OAAO;AAAA,MAChE,UAAU;AAAA,MACV;AAAA,IACF,CAAC;AAAA,IAED,MAAM,cAAc,IAAI;AAAA,IACxB,WAAW,SAAS,QAAQ;AAAA,MAC1B,IAAI,MAAM,SAAS,kBAAkB;AAAA,QACnC,IAAI,CAAC,YAAY,IAAI,MAAM,IAAI,GAAG;AAAA,UAChC,YAAY,IAAI,MAAM,MAAM,CAAC,CAAC;AAAA,QAChC;AAAA,QACA,MAAM,MAAM,YAAY,IAAI,MAAM,IAAI;AAAA,QAEtC,OAAO,IAAI,UAAU,MAAM,gBAAgB;AAAA,UACzC,IAAI,KAAK,EAAE;AAAA,QACb;AAAA,QACA,IAAI,MAAM,kBAAkB,MAAM;AAAA,MACpC;AAAA,IACF;AAAA,IACA,OAAO;AAAA;AAAA,OAMK,YAAW,CAAC,cAAsB,OAAe,QAA+B;AAAA,IAC5F,MAAM,UAAU,cAAc,cAAc,OAAO,MAAM;AAAA,IACzD,IAAI,YAAY,yBAAwB;AAAA,IACxC,IAAI,gBAA+B;AAAA,IACnC,IAAI,iBAA+B;AAAA,IAEnC,IAAI;AAAA,MAEF,MAAM,eAAe,KAAK,cAAc,IAAI,YAAY;AAAA,MACxD,IAAI,CAAC,cAAc;AAAA,QACjB,MAAM,IAAI,MAAM,YAAY,iCAAiC;AAAA,MAC/D;AAAA,MAEA,MAAM,OAAO,aAAa,MAAM,KAAK,CAAC,MAAM,EAAE,OAAO,MAAM;AAAA,MAC3D,IAAI,CAAC,MAAM;AAAA,QACT,MAAM,IAAI,MAAM,QAAQ,gCAAgC,cAAc;AAAA,MACxE;AAAA,MAIA,MAAM,cAAc,MAAM,KAAK,QAAQ,mBAAmB,cAAc,OAAO,QAAQ,KAAK,UAAU;AAAA,QACpG,cAAc,OAAO,KAAK,KAAK,YAAY;AAAA,QAC3C,WAAW;AAAA,QACX,eAAe;AAAA,MACjB,CAAC;AAAA,MAED,IAAI,CAAC,aAAa;AAAA,QAChB,QAAQ,IAAI,eAAe,KAAK,qBAAqB,2BAA2B;AAAA,QAChF;AAAA,MACF;AAAA,MAEA,gBAAgB,YAAY;AAAA,MAC5B,YAAY,yBAAwB;AAAA,MAGpC,iBAAiB,YAAY,MAAM;AAAA,QACjC,IAAI,kBAAkB;AAAA,UAAM;AAAA,QAC5B,KAAK,QAAQ,kBAAkB,cAAc,OAAO,QAAQ,KAAK,UAAU,aAAa,EAAE,MAAM,CAAC,QAAQ;AAAA,UACvG,QAAQ,MAAM,eAAe,KAAK,yCAAyC,YAAY,GAAG;AAAA,SAC3F;AAAA,SACA,KAAK,QAAQ,iBAAiB;AAAA,MAEjC,MAAM,eAAe;AAAA,MAErB,KAAK,YAAY,IAAI,SAAS;AAAA,QAC5B;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,gBAAgB;AAAA,MAClB,CAAC;AAAA,MAED,KAAK,MAAM;AAAA,MAEX,QAAQ,IAAI,eAAe,KAAK,uBAAuB,KAAK,iBAAiB,gBAAgB;AAAA,MAG7F,MAAM,oBAAoB,MAAM,sBAAsB,MAAM,KAAK,SAAS,cAAc,KAAK;AAAA,MAG7F,MAAM,iBAAiB,MAAM,mBAAmB,KAAK,SAAS,cAAc,KAAK;AAAA,MACjF,MAAM,oBAAoB,qBAAqB,cAAc;AAAA,MAC7D,IAAI,gBAAyB;AAAA,MAE7B,IAAI,qBAAqB,kBAAkB,UAAU,WAAW;AAAA,QAE9D,gBAAgB,KAAK,MAAM,kBAAkB,KAAK;AAAA,MACpD;AAAA,MAGA,IAAI,aAAa,aAAa;AAAA,QAC5B,MAAM,kBAAkB,gCAAgC,cAAc;AAAA,QACtE,IAAI,mBAAmB,gBAAgB,SAAS;AAAA,UAG9C,MAAM,cAAc,aAAa,YAAY,UAAU,iBAAiB,CAAC,CAAC;AAAA,UAC1E,IAAI,YAAY,SAAS;AAAA,YACvB,gBAAgB,YAAY;AAAA,UAC9B;AAAA,QACF;AAAA,MACF;AAAA,MAGA,MAAM,MAAM;AAAA,QACV;AAAA,QACA,UAAU;AAAA,UACR,MAAM;AAAA,UACN,MAAM,aAAa,SAAS;AAAA,QAC9B;AAAA,QACA,OAAO;AAAA,QACP,KAAK,IAAI,SAAgB;AAAA,UACvB,QAAQ,IAAI,IAAI,KAAK,SAAS,GAAG,IAAI;AAAA;AAAA,MAEzC;AAAA,MAIA,MAAM,WAAW,KAAK,KAAK,KAAK,SAAS;AAAA,MACzC,MAAM,sBAAsB,qBAAqB,kBAAkB,YAC/D,KAAK,MAAM,kBAAkB,YAAY,IAAI,IAC7C;AAAA,MACJ,MAAM,UAAU,KAAK,aAAa,uBAAuB;AAAA,MAGzD,MAAM,sBAAsB,MAAM,KAAK,0BACrC,cACA,OACA,MACF;AAAA,MAEA,MAAM,kBAAkB,IAAI;AAAA,MAC5B,MAAM,mBAAmB,qBACvB,UACA,KAAK,IACL,mBACA,KACA,eACA,KAAK,SAEL,OAAO,QAAQ;AAAA,QAEb,MAAM,WAAqF;AAAA,UACzF;AAAA,UACA;AAAA,UACA,UAAU;AAAA,UACV,MAAM;AAAA,UACN;AAAA,UACA,QAAQ,IAAI;AAAA,UACZ,SAAS,IAAI;AAAA,UACb;AAAA,UACA,aAAa,IAAI;AAAA,QACnB;AAAA,QACA,MAAM,KAAK,QAAQ,YAAY,cAAc,OAAO,QAAe;AAAA,SAGrE,OAAO,eAA+B;AAAA,QAEpC,IAAI;AAAA,QAGJ,IAAI;AAAA,QACJ,IAAI,cAAc,WAAW;AAAA,QAC7B,IAAI;AAAA,UACF,MAAM,SAAS,KAAK,MAAM,WAAW,IAAI;AAAA,UACzC,IAAI,QAAQ,mBAAmB;AAAA,YAC7B,mBAAmB,OAAO;AAAA,YAC1B,OAAO,OAAO;AAAA,UAChB;AAAA,UACA,IAAI,QAAQ,QAAQ;AAAA,YAClB,QAAQ,OAAO;AAAA,YACf,OAAO,OAAO;AAAA,UAChB;AAAA,UAEA,cAAc,KAAK,UAAU,MAAM;AAAA,UACnC,MAAM;AAAA,QAIR,MAAM,KAAK,QAAQ,mBAAmB,cAAc,OAAO,QAAQ;AAAA,UACjE,MAAM,WAAW;AAAA,UACjB,gBAAgB,WAAW;AAAA,UAC3B;AAAA,UACA,MAAM;AAAA,UACN;AAAA,UACA;AAAA,QACF,CAAC;AAAA,SAGH,OAAO,YAAkC;AAAA,QACvC,MAAM,KAAK,QAAQ,yBAAyB,cAAc,OAAO,QAAQ;AAAA,UACvE,MAAM,QAAQ;AAAA,UACd,gBAAgB,QAAQ;AAAA,UACxB;AAAA,UACA,OAAO,KAAK,MAAM,QAAQ,KAAK;AAAA,QACjC,CAAC;AAAA,SAEH,qBACA;AAAA,QACE,QAAQ,gBAAgB;AAAA,MAC1B,CACF;AAAA,MAEA,MAAM,eAAe,WAAW,MAAM;AAAA,QACpC,gBAAgB,MAAM,IAAI,MAAM,sBAAsB,WAAW,CAAC;AAAA,SACjE,OAAO;AAAA,MAEV,QAAQ,QAAQ,WAAW,MAAM,iBAAiB,QAAQ,MAAM;AAAA,QAC9D,aAAa,YAAY;AAAA,OAC1B;AAAA,MAED,MAAM,UAAU,yBAAwB;AAAA,MACxC,MAAM,WAAW,UAAU;AAAA,MAM3B,MAAM,KAAK,QAAQ,iBACjB,cACA,OACA,QACA,QACA;AAAA,QACE,WAAW;AAAA,QACX;AAAA,QACA;AAAA,QACA;AAAA,MACF,GACA,KAAK,gBAAgB,KACvB;AAAA,MAEA,QAAQ,IAAI,eAAe,KAAK,uBAAuB,KAAK,MAAM;AAAA,MAGlE,IAAI,gBAAgB;AAAA,QAClB,cAAc,cAAc;AAAA,QAC5B,iBAAiB;AAAA,MACnB;AAAA,MACA,KAAK,YAAY,OAAO,OAAO;AAAA,MAC/B,KAAK,MAAM;AAAA,MACX,KAAK,MAAM;AAAA,MAGX,IAAI,KAAK,QAAQ,SAAS,WAAW;AAAA,QACnC,MAAM,gBAAe,KAAK,cAAc,IAAI,YAAY;AAAA,QACxD,IAAI,eAAc;AAAA,UAChB,MAAM,YAAY,MAAM,wBACtB,KAAK,SACL,cACA,OACA,QACA,cAAa,KACf;AAAA,UACA,IAAI,UAAU,SAAS,GAAG;AAAA,YACxB,QAAQ,IACN,eAAe,KAAK,yCAAyC,UAAU,KAAK,IAAI,GAClF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,MACA,OAAO,OAAO;AAAA,MACd,MAAM,iBAAiB,kBAAkB,OAAO,oBAAoB;AAAA,MACpE,QAAQ,MAAM,eAAe,KAAK,aAAa,kBAAkB,YAAY,KAAK;AAAA,MAElF,MAAM,aAAa,KAAK,YAAY,IAAI,OAAO;AAAA,MAC/C,IAAI,YAAY;AAAA,QACd,cAAc,WAAW,cAAc;AAAA,QACvC,KAAK,YAAY,OAAO,OAAO;AAAA,QAC/B,KAAK,MAAM;AAAA,MACb,EAAO,SAAI,gBAAgB;AAAA,QACzB,cAAc,cAAc;AAAA,QAC5B,iBAAiB;AAAA,MACnB;AAAA,MAEA,IAAI,kBAAkB,MAAM;AAAA,QAC1B;AAAA,MACF;AAAA,MAEA,KAAK,MAAM;AAAA,MAGX,MAAM,eAAe,KAAK,cAAc,IAAI,YAAY;AAAA,MACxD,IAAI,CAAC,cAAc;AAAA,QACjB,QAAQ,MAAM,eAAe,KAAK,sBAAsB,iCAAiC;AAAA,QACzF;AAAA,MACF;AAAA,MAGA,MAAM,UAAS,cAAc,OAAO;AAAA,MACpC,IAAI,CAAC,SAAQ;AAAA,QACX,QAAQ,MAAM,eAAe,KAAK,qCAAqC,SAAS;AAAA,QAChF;AAAA,MACF;AAAA,MACA,MAAM,OAAO,aAAa,MAAM,KAAK,CAAC,MAAM,EAAE,OAAO,OAAM;AAAA,MAC3D,IAAI,CAAC,MAAM;AAAA,QACT,QAAQ,MAAM,eAAe,KAAK,kBAAkB,iCAAgC,cAAc;AAAA,QAClG;AAAA,MACF;AAAA,MAGA,MAAM,SAAS,MAAM,KAAK,QAAQ,WAAW,cAAc,OAAO,EAAE,UAAU,QAAQ,gBAAO,CAAC;AAAA,MAC9F,MAAM,QAAQ,kBAAiB,QAAQ,YAAY;AAAA,MACnD,MAAM,uBAAuB,MAAM;AAAA,MAEnC,MAAM,UAAU,yBAAwB;AAAA,MACxC,MAAM,WAAW,WAAW,MAAM,aAAa;AAAA,MAG/C,MAAM,YAAY,eAAe,KAAK;AAAA,MAGtC,IAAI,iBAAiB,UAAU,MAAM,SAAS,UAAU,iBAAiB,OAAO;AAAA,QAC9E,MAAM,YAAY;AAAA,QAElB,MAAM,eAAe,KAAK,SAAS,cAAc,OAAO,SAAQ,WAAW,UAAU,oBAAoB;AAAA,QAEzG,QAAQ,IAAI,eAAe,KAAK,qBAAqB,KAAK,SAAS,UAAU,UAAU,UAAU,SAAS;AAAA,QAG1G,IAAI,KAAK,QAAQ,SAAS,WAAW;AAAA,UACnC,MAAM,gBAAe,KAAK,cAAc,IAAI,YAAY;AAAA,UACxD,IAAI,eAAc;AAAA,YAChB,MAAM,YAAY,KAAK,SAAS,cAAc,OAAO,SAAQ,cAAa,OAAO,KAAK,QAAQ;AAAA,UAChG;AAAA,QACF;AAAA,QAEA;AAAA,MACF;AAAA,MAGA,IAAI,oBAAoB,KAAK,GAAG;AAAA,QAC9B,MAAM,KAAK,QAAQ,eAAe,cAAc,OAAO,SAAQ,WAAW;AAAA,UACxE;AAAA,UACA,eAAe;AAAA,UACf,UAAU;AAAA,UACV,eAAe;AAAA,QACjB,CAAC;AAAA,QAED,QAAQ,IAAI,eAAe,KAAK,kCAAkC,KAAK,4BAA4B;AAAA,QACnG;AAAA,MACF;AAAA,MAGA,MAAM,WAAW,qBAAqB,IAAI;AAAA,MAG1C,IAAI,CAAC,YAAY,SAAS,WAAW,GAAG;AAAA,QACtC,MAAM,KAAK,QAAQ,eAAe,cAAc,OAAO,SAAQ,WAAW;AAAA,UACxE;AAAA,UACA,eAAe;AAAA,UACf,UAAU;AAAA,UACV,eAAe;AAAA,QACjB,CAAC;AAAA,QAED,QAAQ,IAAI,eAAe,KAAK,kCAAkC,KAAK,wBAAwB;AAAA,QAC/F;AAAA,MACF;AAAA,MAGA,MAAM,oBAAoB,uBAAuB;AAAA,MACjD,MAAM,eAAe,iBAAiB,mBAAmB,QAAQ;AAAA,MAEjE,IAAI,aAAa,WAAW;AAAA,QAE1B,MAAM,KAAK,QAAQ,eAAe,cAAc,OAAO,SAAQ,WAAW;AAAA,UACxE;AAAA,UACA,eAAe;AAAA,UACf,UAAU;AAAA,UACV,eAAe;AAAA,QACjB,CAAC;AAAA,QAED,MAAM,gBAAgB,iBAAiB,QAAQ;AAAA,QAC/C,QAAQ,IAAI,eAAe,KAAK,kCAAkC,KAAK,mBAAmB,iCAAiC,SAAS,kBAAkB;AAAA,MACxJ,EAAO;AAAA,QAGL,IAAI,eAAe,aAAa,aAAa,OAAO,SAAS,aAAa,eAAe;AAAA,QACzF,IAAI,iBAAiB,KAAK,KAAK,MAAM,YAAY,WAAW;AAAA,UAC1D,eAAe,MAAM;AAAA,QACvB;AAAA,QAEA,MAAM,cAAc,yBAAwB,IAAI,eAAe;AAAA,QAG/D,MAAM,KAAK,QAAQ,+BACjB,cACA,OACA,SACA,WACA;AAAA,UACE;AAAA,UACA,eAAe;AAAA,UACf;AAAA,UACA,eAAe;AAAA,UACf,aAAa,aAAa;AAAA,UAC1B,iBAAiB,aAAa;AAAA,QAChC,GACA;AAAA,UACE,aAAa;AAAA,UACb;AAAA,UACA;AAAA,UACA,eAAe,SAAS;AAAA,UACxB,aAAa,aAAa;AAAA,UAC1B,iBAAiB,aAAa;AAAA,QAChC,CACF;AAAA,QAEA,MAAM,gBAAgB,iBAAiB,QAAQ;AAAA,QAC/C,QAAQ,IACN,eAAe,KAAK,iCAAiC,KAAK,iBAAiB,qBAAqB,yBAAyB,aAAa,cAAc,KAAK,SAAS,iBAAiB,iBACrL;AAAA;AAAA;AAAA;AAAA,EAQE,mBAAmB,GAAS;AAAA,IAClC,MAAM,WAAW,OAAO,WAAmB;AAAA,MACzC,QAAQ,IAAI,eAAe,KAAK,sBAAsB,qCAAqC;AAAA,MAC3F,MAAM,KAAK,KAAK;AAAA,MAChB,QAAQ,KAAK,CAAC;AAAA;AAAA,IAGhB,QAAQ,GAAG,WAAW,MAAM,SAAS,SAAS,CAAC;AAAA,IAC/C,QAAQ,GAAG,UAAU,MAAM,SAAS,QAAQ,CAAC;AAAA;AAAA,EAGvC;AACV;",
|
|
16
|
+
"debugId": "BD80EAAD1E5949DE64756E2164756E21",
|
|
15
17
|
"names": []
|
|
16
18
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retry utilities for the worker package
|
|
3
|
+
*/
|
|
4
|
+
export { getCurrentPolicy, computeDelay, convertLegacyRetryConfig, getTotalAttempts, resolveRetryPolicies, type PolicyResolutionResult, } from "./policy-resolver";
|
|
5
|
+
export { RetryableError, NonRetryableError, isRetryableError, isNonRetryableError, } from "@cascade-flow/workflow";
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/retry/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,wBAAwB,EACxB,gBAAgB,EAChB,oBAAoB,EACpB,KAAK,sBAAsB,GAC5B,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retry policy resolution and delay computation
|
|
3
|
+
*
|
|
4
|
+
* This module provides stateless functions for computing retry behavior
|
|
5
|
+
* from attempt numbers and policy configurations.
|
|
6
|
+
*/
|
|
7
|
+
import type { RetryPolicy, BackoffConfig } from "@cascade-flow/workflow";
|
|
8
|
+
/**
|
|
9
|
+
* Result of policy resolution when a policy is found
|
|
10
|
+
*/
|
|
11
|
+
export type PolicyResolutionResult = {
|
|
12
|
+
exhausted: false;
|
|
13
|
+
policy: RetryPolicy;
|
|
14
|
+
policyIndex: number;
|
|
15
|
+
attemptInPolicy: number;
|
|
16
|
+
} | {
|
|
17
|
+
exhausted: true;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Get the current policy for an attempt number
|
|
21
|
+
*
|
|
22
|
+
* @param attemptNumber - 1-indexed attempt number (the attempt we're about to make)
|
|
23
|
+
* @param policies - Array of retry policies
|
|
24
|
+
* @returns Policy resolution result
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* const policies = [
|
|
29
|
+
* { maxAttempts: 10, backoff: { type: "exponential", ... } },
|
|
30
|
+
* { maxAttempts: 10, backoff: { type: "constant", delayMs: 3600000 } },
|
|
31
|
+
* ];
|
|
32
|
+
*
|
|
33
|
+
* getCurrentPolicy(1, policies) // → policy 0, attemptInPolicy 1
|
|
34
|
+
* getCurrentPolicy(10, policies) // → policy 0, attemptInPolicy 10
|
|
35
|
+
* getCurrentPolicy(11, policies) // → policy 1, attemptInPolicy 1
|
|
36
|
+
* getCurrentPolicy(21, policies) // → exhausted
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare function getCurrentPolicy(attemptNumber: number, policies: RetryPolicy[]): PolicyResolutionResult;
|
|
40
|
+
/**
|
|
41
|
+
* Compute the delay for a given policy and attempt within that policy
|
|
42
|
+
*
|
|
43
|
+
* @param backoff - Backoff configuration
|
|
44
|
+
* @param attemptInPolicy - 1-indexed attempt number within the policy
|
|
45
|
+
* @returns Delay in milliseconds
|
|
46
|
+
*/
|
|
47
|
+
export declare function computeDelay(backoff: BackoffConfig, attemptInPolicy: number): number;
|
|
48
|
+
/**
|
|
49
|
+
* Convert legacy retry configuration to the new policy format
|
|
50
|
+
*
|
|
51
|
+
* @param maxRetries - Legacy maxRetries value (number of retries, not total attempts)
|
|
52
|
+
* @param retryDelayMs - Legacy retryDelayMs value
|
|
53
|
+
* @returns Array of retry policies, or undefined if no retry config
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```typescript
|
|
57
|
+
* // maxRetries=3 means 4 total attempts (1 initial + 3 retries)
|
|
58
|
+
* convertLegacyRetryConfig(3, 1000)
|
|
59
|
+
* // → [{ maxAttempts: 4, backoff: { type: "constant", delayMs: 1000 } }]
|
|
60
|
+
*
|
|
61
|
+
* convertLegacyRetryConfig(0, 0)
|
|
62
|
+
* // → undefined (no retries)
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export declare function convertLegacyRetryConfig(maxRetries?: number, retryDelayMs?: number): RetryPolicy[] | undefined;
|
|
66
|
+
/**
|
|
67
|
+
* Get the total number of attempts across all policies
|
|
68
|
+
*/
|
|
69
|
+
export declare function getTotalAttempts(policies: RetryPolicy[]): number;
|
|
70
|
+
/**
|
|
71
|
+
* Resolve effective retry policies from step configuration
|
|
72
|
+
* Prefers new `retry` array over legacy `maxRetries`/`retryDelayMs`
|
|
73
|
+
*
|
|
74
|
+
* @param step - Step with retry configuration
|
|
75
|
+
* @returns Resolved retry policies or undefined
|
|
76
|
+
*/
|
|
77
|
+
export declare function resolveRetryPolicies(step: {
|
|
78
|
+
retry?: RetryPolicy[];
|
|
79
|
+
maxRetries?: number;
|
|
80
|
+
retryDelayMs?: number;
|
|
81
|
+
}): RetryPolicy[] | undefined;
|
|
82
|
+
//# sourceMappingURL=policy-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy-resolver.d.ts","sourceRoot":"","sources":["../../src/retry/policy-resolver.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEzE;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAC9B;IACE,SAAS,EAAE,KAAK,CAAC;IACjB,MAAM,EAAE,WAAW,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;CACzB,GACD;IACE,SAAS,EAAE,IAAI,CAAC;CACjB,CAAC;AAEN;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,gBAAgB,CAC9B,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,WAAW,EAAE,GACtB,sBAAsB,CAqBxB;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,GAAG,MAAM,CA0BpF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,wBAAwB,CACtC,UAAU,CAAC,EAAE,MAAM,EACnB,YAAY,CAAC,EAAE,MAAM,GACpB,WAAW,EAAE,GAAG,SAAS,CAiB3B;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,WAAW,EAAE,GAAG,MAAM,CAEhE;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,KAAK,CAAC,EAAE,WAAW,EAAE,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG,WAAW,EAAE,GAAG,SAAS,CAQ5B"}
|
|
@@ -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;
|
|
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;AA0B/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;IA2YzB;;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.
|
|
3
|
+
"version": "0.2.8",
|
|
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.
|
|
22
|
-
"@cascade-flow/backend-filesystem": "0.2.
|
|
23
|
-
"@cascade-flow/runner": "0.2.
|
|
24
|
-
"@cascade-flow/workflow": "0.
|
|
21
|
+
"@cascade-flow/backend-interface": "0.2.6",
|
|
22
|
+
"@cascade-flow/backend-filesystem": "0.2.8",
|
|
23
|
+
"@cascade-flow/runner": "0.2.8",
|
|
24
|
+
"@cascade-flow/workflow": "0.3.1"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@types/bun": "latest",
|