@aikirun/workflow 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -24
- package/dist/index.d.ts +188 -77
- package/dist/index.js +596 -198
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -16,10 +16,10 @@ npm install @aikirun/workflow
|
|
|
16
16
|
import { workflow } from "@aikirun/workflow";
|
|
17
17
|
import { markUserVerified, sendVerificationEmail } from "./tasks.ts";
|
|
18
18
|
|
|
19
|
-
export const onboardingWorkflow = workflow({
|
|
19
|
+
export const onboardingWorkflow = workflow({ name: "user-onboarding" });
|
|
20
20
|
|
|
21
|
-
export const onboardingWorkflowV1 = onboardingWorkflow.v("1.0", {
|
|
22
|
-
async handler(input: { email: string }
|
|
21
|
+
export const onboardingWorkflowV1 = onboardingWorkflow.v("1.0.0", {
|
|
22
|
+
async handler(run, input: { email: string }) {
|
|
23
23
|
run.logger.info("Starting onboarding", { email: input.email });
|
|
24
24
|
|
|
25
25
|
// Execute a task to send verification email
|
|
@@ -30,7 +30,7 @@ export const onboardingWorkflowV1 = onboardingWorkflow.v("1.0", {
|
|
|
30
30
|
await markUserVerified.start(run, { email: input.email });
|
|
31
31
|
|
|
32
32
|
// Sleep for 24 hours before sending tips
|
|
33
|
-
await run.sleep(
|
|
33
|
+
await run.sleep("onboarding-delay", { days: 1 });
|
|
34
34
|
|
|
35
35
|
// Send usage tips
|
|
36
36
|
await sendUsageTips.start(run, { email: input.email });
|
|
@@ -64,9 +64,9 @@ const result = await createUserProfile.start(run, {
|
|
|
64
64
|
|
|
65
65
|
```typescript
|
|
66
66
|
// Sleep requires a unique id for memoization
|
|
67
|
-
await run.sleep(
|
|
68
|
-
await run.sleep(
|
|
69
|
-
await run.sleep(
|
|
67
|
+
await run.sleep("daily-delay", { days: 1 });
|
|
68
|
+
await run.sleep("processing-delay", { hours: 2, minutes: 30 });
|
|
69
|
+
await run.sleep("short-pause", { seconds: 30 });
|
|
70
70
|
```
|
|
71
71
|
|
|
72
72
|
### Sleep Cancellation
|
|
@@ -81,7 +81,7 @@ await handle.wake(); // Wakes the workflow if sleeping
|
|
|
81
81
|
The sleep returns a result indicating whether it was cancelled:
|
|
82
82
|
|
|
83
83
|
```typescript
|
|
84
|
-
const { cancelled } = await run.sleep(
|
|
84
|
+
const { cancelled } = await run.sleep("wait-period", { hours: 1 });
|
|
85
85
|
if (cancelled) {
|
|
86
86
|
// Handle early wake-up
|
|
87
87
|
}
|
|
@@ -106,7 +106,7 @@ run.logger.debug("User created", { userId: result.userId });
|
|
|
106
106
|
### Delayed Trigger
|
|
107
107
|
|
|
108
108
|
```typescript
|
|
109
|
-
export const morningWorkflowV1 = morningWorkflow.v("1.0", {
|
|
109
|
+
export const morningWorkflowV1 = morningWorkflow.v("1.0.0", {
|
|
110
110
|
// ... workflow definition
|
|
111
111
|
opts: {
|
|
112
112
|
trigger: {
|
|
@@ -120,7 +120,7 @@ export const morningWorkflowV1 = morningWorkflow.v("1.0", {
|
|
|
120
120
|
### Retry Strategy
|
|
121
121
|
|
|
122
122
|
```typescript
|
|
123
|
-
export const paymentWorkflowV1 = paymentWorkflow.v("1.0", {
|
|
123
|
+
export const paymentWorkflowV1 = paymentWorkflow.v("1.0.0", {
|
|
124
124
|
// ... workflow definition
|
|
125
125
|
opts: {
|
|
126
126
|
retry: {
|
|
@@ -133,15 +133,18 @@ export const paymentWorkflowV1 = paymentWorkflow.v("1.0", {
|
|
|
133
133
|
});
|
|
134
134
|
```
|
|
135
135
|
|
|
136
|
-
###
|
|
136
|
+
### Reference ID
|
|
137
137
|
|
|
138
138
|
```typescript
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
139
|
+
// Assign a reference ID for tracking and lookup
|
|
140
|
+
const handle = await orderWorkflowV1
|
|
141
|
+
.with().opt("reference.id", `order-${orderId}`)
|
|
142
|
+
.start(client, { orderId });
|
|
143
|
+
|
|
144
|
+
// Configure conflict handling: "error" (default) or "return_existing"
|
|
145
|
+
const handle = await orderWorkflowV1
|
|
146
|
+
.with().opt("reference", { id: `order-${orderId}`, onConflict: "return_existing" })
|
|
147
|
+
.start(client, { orderId });
|
|
145
148
|
```
|
|
146
149
|
|
|
147
150
|
## Running Workflows
|
|
@@ -153,7 +156,7 @@ import { client } from "@aikirun/client";
|
|
|
153
156
|
import { onboardingWorkflowV1 } from "./workflows.ts";
|
|
154
157
|
|
|
155
158
|
const aikiClient = await client({
|
|
156
|
-
url: "http://localhost:
|
|
159
|
+
url: "http://localhost:9876",
|
|
157
160
|
redis: { host: "localhost", port: 6379 },
|
|
158
161
|
});
|
|
159
162
|
|
|
@@ -180,7 +183,7 @@ With a worker:
|
|
|
180
183
|
import { worker } from "@aikirun/worker";
|
|
181
184
|
|
|
182
185
|
const aikiWorker = worker({
|
|
183
|
-
|
|
186
|
+
name: "my-worker",
|
|
184
187
|
workflows: [onboardingWorkflowV1],
|
|
185
188
|
opts: {
|
|
186
189
|
maxConcurrentWorkflowRuns: 10,
|
|
@@ -199,7 +202,7 @@ interface WorkflowRunContext<Input, Output> {
|
|
|
199
202
|
id: WorkflowRunId; // Unique run ID
|
|
200
203
|
name: WorkflowName; // Workflow name
|
|
201
204
|
versionId: WorkflowVersionId; // Version ID
|
|
202
|
-
options: WorkflowOptions; // Execution options (trigger, retry,
|
|
205
|
+
options: WorkflowOptions; // Execution options (trigger, retry, reference)
|
|
203
206
|
handle: WorkflowRunHandle<Input, Output>; // Advanced state management
|
|
204
207
|
logger: Logger; // Logging (info, debug, warn, error, trace)
|
|
205
208
|
sleep(params: SleepParams): Promise<SleepResult>; // Durable sleep
|
|
@@ -210,7 +213,7 @@ Sleep parameters:
|
|
|
210
213
|
- `id` (required): Unique identifier for memoization
|
|
211
214
|
- Duration fields: `days`, `hours`, `minutes`, `seconds`, `milliseconds`
|
|
212
215
|
|
|
213
|
-
Example: `run.sleep(
|
|
216
|
+
Example: `run.sleep("my-sleep", { days: 1, hours: 2 })`
|
|
214
217
|
|
|
215
218
|
## Error Handling
|
|
216
219
|
|
|
@@ -229,9 +232,11 @@ Failed workflows transition to `awaiting_retry` state and are automatically retr
|
|
|
229
232
|
|
|
230
233
|
### Expected Errors
|
|
231
234
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
when
|
|
235
|
+
These errors are thrown during normal workflow execution and should not be caught in workflow code:
|
|
236
|
+
|
|
237
|
+
- `WorkflowRunSuspendedError` - Thrown when a workflow suspends (e.g., during sleep or awaiting events). The worker catches this error and the workflow resumes when the condition is met.
|
|
238
|
+
|
|
239
|
+
- `WorkflowRunConflictError` - Thrown when another worker has already claimed the workflow execution. This prevents duplicate execution when workers race to process the same workflow.
|
|
235
240
|
|
|
236
241
|
## Best Practices
|
|
237
242
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { WorkflowName, WorkflowVersionId } from '@aikirun/types/workflow';
|
|
2
2
|
import { Client, Logger, ApiClient } from '@aikirun/types/client';
|
|
3
3
|
import { INTERNAL } from '@aikirun/types/symbols';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { DurationObject } from '@aikirun/types/duration';
|
|
4
|
+
import { Schema } from '@aikirun/types/validator';
|
|
5
|
+
import { WorkflowRun, TerminalWorkflowRunStatus, WorkflowRunState, WorkflowRunId, WorkflowOptions } from '@aikirun/types/workflow-run';
|
|
6
|
+
import { DurationObject, Duration } from '@aikirun/types/duration';
|
|
7
|
+
import { SleepResult } from '@aikirun/types/sleep';
|
|
7
8
|
import { EventSendOptions, EventWaitOptions, EventWaitState } from '@aikirun/types/event';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { Serializable } from '@aikirun/types/serializable';
|
|
10
|
+
import { DistributiveOmit, RequireAtLeastOneProp } from '@aikirun/types/utils';
|
|
11
|
+
import { TaskId } from '@aikirun/types/task';
|
|
12
|
+
import { WorkflowRunStateRequest, WorkflowRunTransitionTaskStateRequestV1 } from '@aikirun/types/workflow-run-api';
|
|
11
13
|
|
|
12
14
|
type NonEmptyArray<T> = [T, ...T[]];
|
|
13
15
|
|
|
@@ -28,46 +30,89 @@ type PathFromObjectInternal<T, IncludeArrayKeys extends boolean> = And<[
|
|
|
28
30
|
type ExtractObjectType<T> = T extends object ? T : never;
|
|
29
31
|
type TypeOfValueAtPath<T extends object, Path extends PathFromObject<T>> = Path extends keyof T ? T[Path] : Path extends `${infer First}.${infer Rest}` ? First extends keyof T ? undefined extends T[First] ? Rest extends PathFromObject<ExtractObjectType<T[First]>> ? TypeOfValueAtPath<ExtractObjectType<T[First]>, Rest> | undefined : never : Rest extends PathFromObject<ExtractObjectType<T[First]>> ? TypeOfValueAtPath<ExtractObjectType<T[First]>, Rest> : never : never : never;
|
|
30
32
|
|
|
31
|
-
declare function workflowRunHandle<Input, Output, TEventsDefinition extends EventsDefinition>(client: Client
|
|
32
|
-
declare function workflowRunHandle<Input, Output, TEventsDefinition extends EventsDefinition>(client: Client
|
|
33
|
-
interface WorkflowRunHandle<Input, Output, TEventsDefinition extends EventsDefinition = EventsDefinition> {
|
|
33
|
+
declare function workflowRunHandle<Input, Output, AppContext, TEventsDefinition extends EventsDefinition>(client: Client<AppContext>, id: WorkflowRunId, eventsDefinition?: TEventsDefinition, logger?: Logger): Promise<WorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>>;
|
|
34
|
+
declare function workflowRunHandle<Input, Output, AppContext, TEventsDefinition extends EventsDefinition>(client: Client<AppContext>, run: WorkflowRun<Input, Output>, eventsDefinition?: TEventsDefinition, logger?: Logger): Promise<WorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>>;
|
|
35
|
+
interface WorkflowRunHandle<Input, Output, AppContext, TEventsDefinition extends EventsDefinition = EventsDefinition> {
|
|
34
36
|
run: Readonly<WorkflowRun<Input, Output>>;
|
|
35
37
|
events: EventSenders<TEventsDefinition>;
|
|
36
38
|
refresh: () => Promise<void>;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Waits for the child workflow run to reach a terminal status by polling.
|
|
41
|
+
*
|
|
42
|
+
* Returns a result object:
|
|
43
|
+
* - `{ success: true, state }` - workflow reached the expected status
|
|
44
|
+
* - `{ success: false, cause }` - workflow did not reach status
|
|
45
|
+
*
|
|
46
|
+
* Possible failure causes:
|
|
47
|
+
* - `"run_terminated"` - workflow reached a terminal state other than expected
|
|
48
|
+
* - `"timeout"` - timeout elapsed (only when timeout option provided)
|
|
49
|
+
* - `"aborted"` - abort signal triggered (only when abortSignal option provided)
|
|
50
|
+
*
|
|
51
|
+
* @param status - The target status to wait for
|
|
52
|
+
* @param options - Optional configuration for polling interval, timeout, and abort signal
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* // Wait indefinitely until completed or the workflow reaches another terminal state
|
|
56
|
+
* const result = await handle.waitForStatus("completed");
|
|
57
|
+
* if (result.success) {
|
|
58
|
+
* console.log(result.state.output);
|
|
59
|
+
* } else {
|
|
60
|
+
* console.log(`Workflow terminated: ${result.cause}`);
|
|
61
|
+
* }
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* // Wait with a timeout
|
|
65
|
+
* const result = await handle.waitForStatus("completed", {
|
|
66
|
+
* timeout: { seconds: 30 }
|
|
67
|
+
* });
|
|
68
|
+
* if (result.success) {
|
|
69
|
+
* console.log(result.state.output);
|
|
70
|
+
* } else if (result.cause === "timeout") {
|
|
71
|
+
* console.log("Timed out waiting for completion");
|
|
72
|
+
* }
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* // Wait with an abort signal
|
|
76
|
+
* const controller = new AbortController();
|
|
77
|
+
* const result = await handle.waitForStatus("completed", {
|
|
78
|
+
* abortSignal: controller.signal
|
|
79
|
+
* });
|
|
80
|
+
* if (!result.success) {
|
|
81
|
+
* console.log(`Wait ended: ${result.cause}`);
|
|
82
|
+
* }
|
|
83
|
+
*/
|
|
84
|
+
waitForStatus<Status extends TerminalWorkflowRunStatus>(status: Status, options?: WorkflowRunWaitOptions<false, false>): Promise<WorkflowRunWaitResult<Status, Output, false, false>>;
|
|
85
|
+
waitForStatus<Status extends TerminalWorkflowRunStatus>(status: Status, options: WorkflowRunWaitOptions<true, false>): Promise<WorkflowRunWaitResult<Status, Output, true, false>>;
|
|
86
|
+
waitForStatus<Status extends TerminalWorkflowRunStatus>(status: Status, options: WorkflowRunWaitOptions<false, true>): Promise<WorkflowRunWaitResult<Status, Output, false, true>>;
|
|
87
|
+
waitForStatus<Status extends TerminalWorkflowRunStatus>(status: Status, options: WorkflowRunWaitOptions<true, true>): Promise<WorkflowRunWaitResult<Status, Output, true, true>>;
|
|
57
88
|
cancel: (reason?: string) => Promise<void>;
|
|
58
89
|
pause: () => Promise<void>;
|
|
59
90
|
resume: () => Promise<void>;
|
|
91
|
+
awake: () => Promise<void>;
|
|
60
92
|
[INTERNAL]: {
|
|
93
|
+
client: Client<AppContext>;
|
|
61
94
|
transitionState: (state: WorkflowRunStateRequest) => Promise<void>;
|
|
62
|
-
transitionTaskState: (
|
|
95
|
+
transitionTaskState: (request: DistributiveOmit<WorkflowRunTransitionTaskStateRequestV1, "id" | "expectedRevision">) => Promise<{
|
|
96
|
+
taskId: TaskId;
|
|
97
|
+
}>;
|
|
63
98
|
assertExecutionAllowed: () => void;
|
|
64
99
|
};
|
|
65
100
|
}
|
|
66
|
-
interface WorkflowRunWaitOptions {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
abortSignal?: AbortSignal;
|
|
101
|
+
interface WorkflowRunWaitOptions<Timed extends boolean, Abortable extends boolean> {
|
|
102
|
+
interval?: DurationObject;
|
|
103
|
+
timeout?: Timed extends true ? DurationObject : never;
|
|
104
|
+
abortSignal?: Abortable extends true ? AbortSignal : never;
|
|
70
105
|
}
|
|
106
|
+
type WorkflowRunWaitResultSuccess<Status extends TerminalWorkflowRunStatus, Output> = Extract<WorkflowRunState<Output>, {
|
|
107
|
+
status: Status;
|
|
108
|
+
}>;
|
|
109
|
+
type WorkflowRunWaitResult<Status extends TerminalWorkflowRunStatus, Output, Timed extends boolean, Abortable extends boolean> = {
|
|
110
|
+
success: false;
|
|
111
|
+
cause: "run_terminated" | (Timed extends true ? "timeout" : never) | (Abortable extends true ? "aborted" : never);
|
|
112
|
+
} | {
|
|
113
|
+
success: true;
|
|
114
|
+
state: WorkflowRunWaitResultSuccess<Status, Output>;
|
|
115
|
+
};
|
|
71
116
|
|
|
72
117
|
/**
|
|
73
118
|
* Defines an event type that can be sent to and waited for by workflows.
|
|
@@ -90,13 +135,11 @@ interface WorkflowRunWaitOptions {
|
|
|
90
135
|
* });
|
|
91
136
|
* ```
|
|
92
137
|
*/
|
|
93
|
-
declare function event
|
|
138
|
+
declare function event(): EventDefinition<void>;
|
|
139
|
+
declare function event<Data extends Serializable>(params?: EventParams<Data>): EventDefinition<Data>;
|
|
94
140
|
interface EventParams<Data> {
|
|
95
141
|
schema?: Schema<Data>;
|
|
96
142
|
}
|
|
97
|
-
interface Schema<Data> {
|
|
98
|
-
parse: (data: unknown) => Data;
|
|
99
|
-
}
|
|
100
143
|
interface EventDefinition<Data> {
|
|
101
144
|
_type: Data;
|
|
102
145
|
schema?: Schema<Data>;
|
|
@@ -107,63 +150,134 @@ type EventWaiters<TEventsDefinition extends EventsDefinition> = {
|
|
|
107
150
|
[K in keyof TEventsDefinition]: EventWaiter<EventData<TEventsDefinition[K]>>;
|
|
108
151
|
};
|
|
109
152
|
interface EventWaiter<Data> {
|
|
110
|
-
wait(options?: EventWaitOptions<
|
|
111
|
-
wait(options: EventWaitOptions<
|
|
153
|
+
wait(options?: EventWaitOptions<false>): Promise<EventWaitState<Data, false>>;
|
|
154
|
+
wait(options: EventWaitOptions<true>): Promise<EventWaitState<Data, true>>;
|
|
112
155
|
}
|
|
113
156
|
type EventSenders<TEventsDefinition extends EventsDefinition> = {
|
|
114
157
|
[K in keyof TEventsDefinition]: EventSender<EventData<TEventsDefinition[K]>>;
|
|
115
158
|
};
|
|
116
159
|
interface EventSender<Data> {
|
|
117
|
-
|
|
160
|
+
with(): EventSenderBuilder<Data>;
|
|
161
|
+
send: (...args: Data extends void ? [] : [Data]) => Promise<void>;
|
|
162
|
+
}
|
|
163
|
+
interface EventSenderBuilder<Data> {
|
|
164
|
+
opt<Path extends PathFromObject<EventSendOptions>>(path: Path, value: TypeOfValueAtPath<EventSendOptions, Path>): EventSenderBuilder<Data>;
|
|
165
|
+
send: (...args: Data extends void ? [] : [Data]) => Promise<void>;
|
|
118
166
|
}
|
|
119
|
-
|
|
167
|
+
type EventMulticasters<TEventsDefinition extends EventsDefinition> = {
|
|
168
|
+
[K in keyof TEventsDefinition]: EventMulticaster<EventData<TEventsDefinition[K]>>;
|
|
169
|
+
};
|
|
170
|
+
interface EventMulticaster<Data> {
|
|
171
|
+
with(): EventMulticasterBuilder<Data>;
|
|
172
|
+
send: <AppContext>(client: Client<AppContext>, runId: string | string[], ...args: Data extends void ? [] : [Data]) => Promise<void>;
|
|
173
|
+
}
|
|
174
|
+
interface EventMulticasterBuilder<Data> {
|
|
175
|
+
opt<Path extends PathFromObject<EventSendOptions>>(path: Path, value: TypeOfValueAtPath<EventSendOptions, Path>): EventMulticasterBuilder<Data>;
|
|
176
|
+
send: <AppContext>(client: Client<AppContext>, runId: string | string[], ...args: Data extends void ? [] : [Data]) => Promise<void>;
|
|
177
|
+
}
|
|
178
|
+
declare function createEventWaiters<TEventsDefinition extends EventsDefinition>(handle: WorkflowRunHandle<unknown, unknown, unknown, TEventsDefinition>, eventsDefinition: TEventsDefinition, logger: Logger): EventWaiters<TEventsDefinition>;
|
|
120
179
|
declare function createEventSenders<TEventsDefinition extends EventsDefinition>(api: ApiClient, workflowRunId: string, eventsDefinition: TEventsDefinition, logger: Logger, onSend: (run: WorkflowRun<unknown, unknown>) => void): EventSenders<TEventsDefinition>;
|
|
121
180
|
|
|
122
|
-
interface WorkflowRunContext<Input,
|
|
181
|
+
interface WorkflowRunContext<Input, AppContext, TEventDefinition extends EventsDefinition> {
|
|
123
182
|
id: WorkflowRunId;
|
|
124
|
-
|
|
125
|
-
|
|
183
|
+
name: WorkflowName;
|
|
184
|
+
versionId: WorkflowVersionId;
|
|
126
185
|
options: WorkflowOptions;
|
|
127
186
|
logger: Logger;
|
|
128
|
-
sleep: (
|
|
187
|
+
sleep: (name: string, duration: Duration) => Promise<SleepResult>;
|
|
129
188
|
events: EventWaiters<TEventDefinition>;
|
|
130
189
|
[INTERNAL]: {
|
|
131
|
-
handle: WorkflowRunHandle<Input,
|
|
190
|
+
handle: WorkflowRunHandle<Input, unknown, AppContext, TEventDefinition>;
|
|
132
191
|
options: {
|
|
133
192
|
spinThresholdMs: number;
|
|
134
193
|
};
|
|
135
194
|
};
|
|
136
195
|
}
|
|
137
196
|
|
|
197
|
+
type ChildWorkflowRunHandle<Input, Output, AppContext, TEventsDefinition extends EventsDefinition = EventsDefinition> = Omit<WorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>, "waitForStatus"> & {
|
|
198
|
+
/**
|
|
199
|
+
* Waits for the child workflow run to reach a terminal status.
|
|
200
|
+
*
|
|
201
|
+
* This method suspends the parent workflow until the child reaches the expected terminal status
|
|
202
|
+
* or the optional timeout elapses.
|
|
203
|
+
*
|
|
204
|
+
* When the parent resumes, the result is deterministically replayed from stored wait results.
|
|
205
|
+
*
|
|
206
|
+
* Returns a result object:
|
|
207
|
+
* - `{ success: true, state }` - child reached the expected status
|
|
208
|
+
* - `{ success: false, cause }` - child did not reach status
|
|
209
|
+
*
|
|
210
|
+
* Possible failure causes:
|
|
211
|
+
* - `"run_terminated"` - child reached a different terminal state than expected
|
|
212
|
+
* - `"timeout"` - timeout elapsed (only when timeout option provided)
|
|
213
|
+
*
|
|
214
|
+
* @param status - The target terminal status to wait for
|
|
215
|
+
* @param options - Optional configuration with timeout
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* // Wait indefinitely for child to complete
|
|
219
|
+
* const result = await childHandle.waitForStatus("completed");
|
|
220
|
+
* if (result.success) {
|
|
221
|
+
* console.log(result.state.output);
|
|
222
|
+
* } else {
|
|
223
|
+
* console.log(`Child terminated: ${result.cause}`);
|
|
224
|
+
* }
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* // Wait with a timeout
|
|
228
|
+
* const result = await childHandle.waitForStatus("completed", {
|
|
229
|
+
* timeout: { minutes: 5 }
|
|
230
|
+
* });
|
|
231
|
+
* if (!result.success && result.cause === "timeout") {
|
|
232
|
+
* console.log("Child workflow took too long");
|
|
233
|
+
* }
|
|
234
|
+
*/
|
|
235
|
+
waitForStatus<Status extends TerminalWorkflowRunStatus>(status: Status, options?: ChildWorkflowRunWaitOptions<false>): Promise<WorkflowRunWaitResult<Status, Output, false, false>>;
|
|
236
|
+
waitForStatus<Status extends TerminalWorkflowRunStatus>(status: Status, options: ChildWorkflowRunWaitOptions<true>): Promise<WorkflowRunWaitResult<Status, Output, true, false>>;
|
|
237
|
+
};
|
|
238
|
+
interface ChildWorkflowRunWaitOptions<Timed extends boolean> {
|
|
239
|
+
timeout?: Timed extends true ? DurationObject : never;
|
|
240
|
+
}
|
|
241
|
+
|
|
138
242
|
interface WorkflowVersionParams<Input, Output, AppContext, TEventsDefinition extends EventsDefinition> {
|
|
243
|
+
handler: (run: Readonly<WorkflowRunContext<Input, AppContext, TEventsDefinition>>, input: Input, context: AppContext) => Promise<Output>;
|
|
139
244
|
events?: TEventsDefinition;
|
|
140
245
|
opts?: WorkflowOptions;
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
start: WorkflowVersion<Input, Output, AppContext, TEventsDefinition>["start"];
|
|
246
|
+
schema?: RequireAtLeastOneProp<{
|
|
247
|
+
input?: Schema<Input>;
|
|
248
|
+
output?: Schema<Output>;
|
|
249
|
+
}>;
|
|
146
250
|
}
|
|
147
251
|
interface WorkflowVersion<Input, Output, AppContext, TEventsDefinition extends EventsDefinition = EventsDefinition> {
|
|
148
|
-
|
|
252
|
+
name: WorkflowName;
|
|
149
253
|
versionId: WorkflowVersionId;
|
|
254
|
+
events: EventMulticasters<TEventsDefinition>;
|
|
150
255
|
with(): WorkflowBuilder<Input, Output, AppContext, TEventsDefinition>;
|
|
151
|
-
start: (client: Client<AppContext>, ...args: Input extends
|
|
152
|
-
|
|
256
|
+
start: (client: Client<AppContext>, ...args: Input extends void ? [] : [Input]) => Promise<WorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>>;
|
|
257
|
+
startAsChild: <ParentInput, ParentEventsDefinition extends EventsDefinition>(parentRun: WorkflowRunContext<ParentInput, AppContext, ParentEventsDefinition>, ...args: Input extends void ? [] : [Input]) => Promise<ChildWorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>>;
|
|
258
|
+
getHandle: (client: Client<AppContext>, runId: WorkflowRunId) => Promise<WorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>>;
|
|
153
259
|
[INTERNAL]: {
|
|
154
260
|
eventsDefinition: TEventsDefinition;
|
|
155
|
-
handler: (
|
|
261
|
+
handler: (run: WorkflowRunContext<Input, AppContext, TEventsDefinition>, input: Input, context: AppContext) => Promise<void>;
|
|
156
262
|
};
|
|
157
263
|
}
|
|
264
|
+
interface WorkflowBuilder<Input, Output, AppContext, TEventsDefinition extends EventsDefinition> {
|
|
265
|
+
opt<Path extends PathFromObject<WorkflowOptions>>(path: Path, value: TypeOfValueAtPath<WorkflowOptions, Path>): WorkflowBuilder<Input, Output, AppContext, TEventsDefinition>;
|
|
266
|
+
start: WorkflowVersion<Input, Output, AppContext, TEventsDefinition>["start"];
|
|
267
|
+
startAsChild: WorkflowVersion<Input, Output, AppContext, TEventsDefinition>["startAsChild"];
|
|
268
|
+
}
|
|
158
269
|
declare class WorkflowVersionImpl<Input, Output, AppContext, TEventsDefinition extends EventsDefinition> implements WorkflowVersion<Input, Output, AppContext, TEventsDefinition> {
|
|
159
|
-
readonly
|
|
270
|
+
readonly name: WorkflowName;
|
|
160
271
|
readonly versionId: WorkflowVersionId;
|
|
161
272
|
private readonly params;
|
|
273
|
+
readonly events: EventMulticasters<TEventsDefinition>;
|
|
162
274
|
readonly [INTERNAL]: WorkflowVersion<Input, Output, AppContext, TEventsDefinition>[typeof INTERNAL];
|
|
163
|
-
constructor(
|
|
275
|
+
constructor(name: WorkflowName, versionId: WorkflowVersionId, params: WorkflowVersionParams<Input, Output, AppContext, TEventsDefinition>);
|
|
164
276
|
with(): WorkflowBuilder<Input, Output, AppContext, TEventsDefinition>;
|
|
165
|
-
start(client: Client<AppContext>, ...args: Input extends
|
|
166
|
-
|
|
277
|
+
start(client: Client<AppContext>, ...args: Input extends void ? [] : [Input]): Promise<WorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>>;
|
|
278
|
+
startAsChild(parentRun: WorkflowRunContext<unknown, AppContext, EventsDefinition>, ...args: Input extends void ? [] : [Input]): Promise<ChildWorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>>;
|
|
279
|
+
private assertUniqueChildRunReferenceId;
|
|
280
|
+
getHandle(client: Client<AppContext>, runId: WorkflowRunId): Promise<WorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>>;
|
|
167
281
|
private handler;
|
|
168
282
|
private tryExecuteWorkflow;
|
|
169
283
|
private assertRetryAllowed;
|
|
@@ -180,13 +294,10 @@ interface WorkflowRegistry {
|
|
|
180
294
|
removeMany: (workflows: Workflow$1[]) => WorkflowRegistry;
|
|
181
295
|
removeAll: () => WorkflowRegistry;
|
|
182
296
|
getAll(): Workflow$1[];
|
|
183
|
-
get: (
|
|
297
|
+
get: (name: WorkflowName, versionId: WorkflowVersionId) => Workflow$1 | undefined;
|
|
184
298
|
}
|
|
185
299
|
|
|
186
|
-
|
|
187
|
-
spinThresholdMs: number;
|
|
188
|
-
}
|
|
189
|
-
declare function createSleeper(handle: WorkflowRunHandle<unknown, unknown>, logger: Logger, options: SleeperOptions): (params: SleepParams) => Promise<SleepResult>;
|
|
300
|
+
declare function createSleeper(handle: WorkflowRunHandle<unknown, unknown, unknown>, logger: Logger): (name: string, duration: Duration) => Promise<SleepResult>;
|
|
190
301
|
|
|
191
302
|
/**
|
|
192
303
|
* Defines a durable workflow with versioning and multiple task execution.
|
|
@@ -196,17 +307,17 @@ declare function createSleeper(handle: WorkflowRunHandle<unknown, unknown>, logg
|
|
|
196
307
|
* Multiple versions of a workflow can run simultaneously, allowing safe deployments.
|
|
197
308
|
*
|
|
198
309
|
* @param params - Workflow configuration
|
|
199
|
-
* @param params.
|
|
310
|
+
* @param params.name - Unique workflow name used for identification and routing
|
|
200
311
|
* @returns Workflow instance with version management methods
|
|
201
312
|
*
|
|
202
313
|
* @example
|
|
203
314
|
* ```typescript
|
|
204
315
|
* // Define a workflow
|
|
205
|
-
* export const userOnboarding = workflow({
|
|
316
|
+
* export const userOnboarding = workflow({ name: "user-onboarding" });
|
|
206
317
|
*
|
|
207
318
|
* // Define version 1.0
|
|
208
|
-
* export const userOnboardingV1 = userOnboarding.v("1.0", {
|
|
209
|
-
* async handler(input: { email: string }
|
|
319
|
+
* export const userOnboardingV1 = userOnboarding.v("1.0.0", {
|
|
320
|
+
* async handler(run, input: { email: string }) {
|
|
210
321
|
* run.logger.info("Starting onboarding", { email: input.email });
|
|
211
322
|
*
|
|
212
323
|
* // Execute tasks
|
|
@@ -214,7 +325,7 @@ declare function createSleeper(handle: WorkflowRunHandle<unknown, unknown>, logg
|
|
|
214
325
|
* await createUserProfile.start(run, { email: input.email });
|
|
215
326
|
*
|
|
216
327
|
* // Durable sleep
|
|
217
|
-
* await run.sleep(
|
|
328
|
+
* await run.sleep("onboarding-delay", { days: 1 });
|
|
218
329
|
*
|
|
219
330
|
* // More tasks
|
|
220
331
|
* await sendUsageTips.start(run, { email: input.email });
|
|
@@ -224,8 +335,8 @@ declare function createSleeper(handle: WorkflowRunHandle<unknown, unknown>, logg
|
|
|
224
335
|
* });
|
|
225
336
|
*
|
|
226
337
|
* // Deploy version 2.0 alongside 1.0 (no downtime)
|
|
227
|
-
* export const userOnboardingV2 = userOnboarding.v("2.0", {
|
|
228
|
-
* async handler(input: { email: string; trial: boolean }
|
|
338
|
+
* export const userOnboardingV2 = userOnboarding.v("2.0.0", {
|
|
339
|
+
* async handler(run, input: { email: string; trial: boolean }) {
|
|
229
340
|
* // Enhanced version with different logic
|
|
230
341
|
* // Existing v1.0 workflows continue with their version
|
|
231
342
|
* // New workflows use v2.0
|
|
@@ -237,15 +348,15 @@ declare function createSleeper(handle: WorkflowRunHandle<unknown, unknown>, logg
|
|
|
237
348
|
*/
|
|
238
349
|
declare function workflow(params: WorkflowParams): Workflow;
|
|
239
350
|
interface WorkflowParams {
|
|
240
|
-
|
|
351
|
+
name: string;
|
|
241
352
|
}
|
|
242
353
|
interface Workflow {
|
|
243
|
-
|
|
244
|
-
v: <Input extends
|
|
354
|
+
name: WorkflowName;
|
|
355
|
+
v: <Input extends Serializable, Output extends Serializable, AppContext = null, TEventsDefinition extends EventsDefinition = Record<string, never>>(versionId: string, params: WorkflowVersionParams<Input, Output, AppContext, TEventsDefinition>) => WorkflowVersion<Input, Output, AppContext, TEventsDefinition>;
|
|
245
356
|
[INTERNAL]: {
|
|
246
357
|
getAllVersions: () => WorkflowVersion<unknown, unknown, unknown>[];
|
|
247
358
|
getVersion: (versionId: WorkflowVersionId) => WorkflowVersion<unknown, unknown, unknown> | undefined;
|
|
248
359
|
};
|
|
249
360
|
}
|
|
250
361
|
|
|
251
|
-
export { type
|
|
362
|
+
export { type EventMulticaster, type EventMulticasters, type EventSender, type EventSenders, type EventWaiter, type EventWaiters, type Workflow, type WorkflowParams, type WorkflowRegistry, type WorkflowRunContext, type WorkflowRunHandle, type WorkflowRunWaitOptions, type WorkflowVersion, WorkflowVersionImpl, type WorkflowVersionParams, createEventSenders, createEventWaiters, createSleeper, event, workflow, workflowRegistry, workflowRunHandle };
|