@aikirun/workflow 0.6.0 → 0.7.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/dist/index.d.ts +144 -45
- package/dist/index.js +288 -82
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { WorkflowId, 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 { WorkflowRun,
|
|
4
|
+
import { WorkflowRun, TerminalWorkflowRunStatus, WorkflowRunState, WorkflowRunId, WorkflowOptions } from '@aikirun/types/workflow-run';
|
|
5
5
|
import { SleepParams, SleepResult } from '@aikirun/types/sleep';
|
|
6
|
-
import { DurationObject } from '@aikirun/types/duration';
|
|
7
6
|
import { EventSendOptions, EventWaitOptions, EventWaitState } from '@aikirun/types/event';
|
|
7
|
+
import { DurationObject } from '@aikirun/types/duration';
|
|
8
8
|
import { TaskPath } from '@aikirun/types/task';
|
|
9
9
|
import { WorkflowRunStateRequest, TaskStateRequest } from '@aikirun/types/workflow-run-api';
|
|
10
|
-
import {
|
|
10
|
+
import { Serializable } from '@aikirun/types/error';
|
|
11
11
|
|
|
12
12
|
type NonEmptyArray<T> = [T, ...T[]];
|
|
13
13
|
|
|
@@ -28,46 +28,87 @@ type PathFromObjectInternal<T, IncludeArrayKeys extends boolean> = And<[
|
|
|
28
28
|
type ExtractObjectType<T> = T extends object ? T : never;
|
|
29
29
|
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
30
|
|
|
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> {
|
|
31
|
+
declare function workflowRunHandle<Input, Output, AppContext, TEventsDefinition extends EventsDefinition>(client: Client<AppContext>, id: WorkflowRunId, eventsDefinition?: TEventsDefinition, logger?: Logger): Promise<WorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>>;
|
|
32
|
+
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>>;
|
|
33
|
+
interface WorkflowRunHandle<Input, Output, AppContext, TEventsDefinition extends EventsDefinition = EventsDefinition> {
|
|
34
34
|
run: Readonly<WorkflowRun<Input, Output>>;
|
|
35
35
|
events: EventSenders<TEventsDefinition>;
|
|
36
36
|
refresh: () => Promise<void>;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
37
|
+
/**
|
|
38
|
+
* Waits for the child workflow run to reach a terminal status by polling.
|
|
39
|
+
*
|
|
40
|
+
* Returns a result object:
|
|
41
|
+
* - `{ success: true, state }` - workflow reached the expected status
|
|
42
|
+
* - `{ success: false, cause }` - workflow did not reach status
|
|
43
|
+
*
|
|
44
|
+
* Possible failure causes:
|
|
45
|
+
* - `"run_terminated"` - workflow reached a terminal state other than expected
|
|
46
|
+
* - `"timeout"` - timeout elapsed (only when timeout option provided)
|
|
47
|
+
* - `"aborted"` - abort signal triggered (only when abortSignal option provided)
|
|
48
|
+
*
|
|
49
|
+
* @param status - The target status to wait for
|
|
50
|
+
* @param options - Optional configuration for polling interval, timeout, and abort signal
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* // Wait indefinitely until completed or the workflow reaches another terminal state
|
|
54
|
+
* const result = await handle.waitForStatus("completed");
|
|
55
|
+
* if (result.success) {
|
|
56
|
+
* console.log(result.state.output);
|
|
57
|
+
* } else {
|
|
58
|
+
* console.log(`Workflow terminated: ${result.cause}`);
|
|
59
|
+
* }
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* // Wait with a timeout
|
|
63
|
+
* const result = await handle.waitForStatus("completed", {
|
|
64
|
+
* timeout: { seconds: 30 }
|
|
65
|
+
* });
|
|
66
|
+
* if (result.success) {
|
|
67
|
+
* console.log(result.state.output);
|
|
68
|
+
* } else if (result.cause === "timeout") {
|
|
69
|
+
* console.log("Timed out waiting for completion");
|
|
70
|
+
* }
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* // Wait with an abort signal
|
|
74
|
+
* const controller = new AbortController();
|
|
75
|
+
* const result = await handle.waitForStatus("completed", {
|
|
76
|
+
* abortSignal: controller.signal
|
|
77
|
+
* });
|
|
78
|
+
* if (!result.success) {
|
|
79
|
+
* console.log(`Wait ended: ${result.cause}`);
|
|
80
|
+
* }
|
|
81
|
+
*/
|
|
82
|
+
waitForStatus<Status extends TerminalWorkflowRunStatus>(status: Status, options?: WorkflowRunWaitOptions<false, false>): Promise<WorkflowRunWaitResult<Status, Output, false, false>>;
|
|
83
|
+
waitForStatus<Status extends TerminalWorkflowRunStatus>(status: Status, options: WorkflowRunWaitOptions<true, false>): Promise<WorkflowRunWaitResult<Status, Output, true, false>>;
|
|
84
|
+
waitForStatus<Status extends TerminalWorkflowRunStatus>(status: Status, options: WorkflowRunWaitOptions<false, true>): Promise<WorkflowRunWaitResult<Status, Output, false, true>>;
|
|
85
|
+
waitForStatus<Status extends TerminalWorkflowRunStatus>(status: Status, options: WorkflowRunWaitOptions<true, true>): Promise<WorkflowRunWaitResult<Status, Output, true, true>>;
|
|
57
86
|
cancel: (reason?: string) => Promise<void>;
|
|
58
87
|
pause: () => Promise<void>;
|
|
59
88
|
resume: () => Promise<void>;
|
|
89
|
+
awake: () => Promise<void>;
|
|
60
90
|
[INTERNAL]: {
|
|
91
|
+
client: Client<AppContext>;
|
|
61
92
|
transitionState: (state: WorkflowRunStateRequest) => Promise<void>;
|
|
62
93
|
transitionTaskState: (taskPath: TaskPath, taskState: TaskStateRequest) => Promise<void>;
|
|
63
94
|
assertExecutionAllowed: () => void;
|
|
64
95
|
};
|
|
65
96
|
}
|
|
66
|
-
interface WorkflowRunWaitOptions {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
abortSignal?: AbortSignal;
|
|
97
|
+
interface WorkflowRunWaitOptions<Timed extends boolean, Abortable extends boolean> {
|
|
98
|
+
interval?: DurationObject;
|
|
99
|
+
timeout?: Timed extends true ? DurationObject : never;
|
|
100
|
+
abortSignal?: Abortable extends true ? AbortSignal : never;
|
|
70
101
|
}
|
|
102
|
+
type WorkflowRunWaitResultSuccess<Status extends TerminalWorkflowRunStatus, Output> = Extract<WorkflowRunState<Output>, {
|
|
103
|
+
status: Status;
|
|
104
|
+
}>;
|
|
105
|
+
type WorkflowRunWaitResult<Status extends TerminalWorkflowRunStatus, Output, Timed extends boolean, Abortable extends boolean> = {
|
|
106
|
+
success: false;
|
|
107
|
+
cause: "run_terminated" | (Timed extends true ? "timeout" : never) | (Abortable extends true ? "aborted" : never);
|
|
108
|
+
} | {
|
|
109
|
+
success: true;
|
|
110
|
+
state: WorkflowRunWaitResultSuccess<Status, Output>;
|
|
111
|
+
};
|
|
71
112
|
|
|
72
113
|
/**
|
|
73
114
|
* Defines an event type that can be sent to and waited for by workflows.
|
|
@@ -90,6 +131,7 @@ interface WorkflowRunWaitOptions {
|
|
|
90
131
|
* });
|
|
91
132
|
* ```
|
|
92
133
|
*/
|
|
134
|
+
declare function event(): EventDefinition<undefined>;
|
|
93
135
|
declare function event<Data>(params?: EventParams<Data>): EventDefinition<Data>;
|
|
94
136
|
interface EventParams<Data> {
|
|
95
137
|
schema?: Schema<Data>;
|
|
@@ -107,19 +149,25 @@ type EventWaiters<TEventsDefinition extends EventsDefinition> = {
|
|
|
107
149
|
[K in keyof TEventsDefinition]: EventWaiter<EventData<TEventsDefinition[K]>>;
|
|
108
150
|
};
|
|
109
151
|
interface EventWaiter<Data> {
|
|
110
|
-
wait(options?: EventWaitOptions<
|
|
111
|
-
wait(options: EventWaitOptions<
|
|
152
|
+
wait(options?: EventWaitOptions<false>): Promise<EventWaitState<Data, false>>;
|
|
153
|
+
wait(options: EventWaitOptions<true>): Promise<EventWaitState<Data, true>>;
|
|
112
154
|
}
|
|
113
155
|
type EventSenders<TEventsDefinition extends EventsDefinition> = {
|
|
114
156
|
[K in keyof TEventsDefinition]: EventSender<EventData<TEventsDefinition[K]>>;
|
|
115
157
|
};
|
|
116
158
|
interface EventSender<Data> {
|
|
117
|
-
send: (data: Data, options?: EventSendOptions) => Promise<void>;
|
|
159
|
+
send: (...args: Data extends undefined ? [data?: Data, options?: EventSendOptions] : [data: Data, options?: EventSendOptions]) => Promise<void>;
|
|
160
|
+
}
|
|
161
|
+
type EventMulticasters<TEventsDefinition extends EventsDefinition> = {
|
|
162
|
+
[K in keyof TEventsDefinition]: EventMulticaster<EventData<TEventsDefinition[K]>>;
|
|
163
|
+
};
|
|
164
|
+
interface EventMulticaster<Data> {
|
|
165
|
+
send: <AppContext>(client: Client<AppContext>, runId: string | string[], data: Data, options?: EventSendOptions) => Promise<void>;
|
|
118
166
|
}
|
|
119
|
-
declare function createEventWaiters<TEventsDefinition extends EventsDefinition>(handle: WorkflowRunHandle<unknown, unknown, TEventsDefinition>, eventsDefinition: TEventsDefinition, logger: Logger): EventWaiters<TEventsDefinition>;
|
|
167
|
+
declare function createEventWaiters<TEventsDefinition extends EventsDefinition>(handle: WorkflowRunHandle<unknown, unknown, unknown, TEventsDefinition>, eventsDefinition: TEventsDefinition, logger: Logger): EventWaiters<TEventsDefinition>;
|
|
120
168
|
declare function createEventSenders<TEventsDefinition extends EventsDefinition>(api: ApiClient, workflowRunId: string, eventsDefinition: TEventsDefinition, logger: Logger, onSend: (run: WorkflowRun<unknown, unknown>) => void): EventSenders<TEventsDefinition>;
|
|
121
169
|
|
|
122
|
-
interface WorkflowRunContext<Input,
|
|
170
|
+
interface WorkflowRunContext<Input, AppContext, TEventDefinition extends EventsDefinition> {
|
|
123
171
|
id: WorkflowRunId;
|
|
124
172
|
workflowId: WorkflowId;
|
|
125
173
|
workflowVersionId: WorkflowVersionId;
|
|
@@ -128,47 +176,98 @@ interface WorkflowRunContext<Input, Output, TEventDefinition extends EventsDefin
|
|
|
128
176
|
sleep: (params: SleepParams) => Promise<SleepResult>;
|
|
129
177
|
events: EventWaiters<TEventDefinition>;
|
|
130
178
|
[INTERNAL]: {
|
|
131
|
-
handle: WorkflowRunHandle<Input,
|
|
179
|
+
handle: WorkflowRunHandle<Input, unknown, AppContext, TEventDefinition>;
|
|
132
180
|
options: {
|
|
133
181
|
spinThresholdMs: number;
|
|
134
182
|
};
|
|
135
183
|
};
|
|
136
184
|
}
|
|
137
185
|
|
|
186
|
+
type ChildWorkflowRunHandle<Input, Output, AppContext, TEventsDefinition extends EventsDefinition = EventsDefinition> = Omit<WorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>, "waitForStatus"> & {
|
|
187
|
+
/**
|
|
188
|
+
* Waits for the child workflow run to reach a terminal status.
|
|
189
|
+
*
|
|
190
|
+
* This method suspends the parent workflow until the child reaches the expected terminal status
|
|
191
|
+
* or the optional timeout elapses.
|
|
192
|
+
*
|
|
193
|
+
* When the parent resumes, the result is deterministically replayed from stored wait results.
|
|
194
|
+
*
|
|
195
|
+
* Returns a result object:
|
|
196
|
+
* - `{ success: true, state }` - child reached the expected status
|
|
197
|
+
* - `{ success: false, cause }` - child did not reach status
|
|
198
|
+
*
|
|
199
|
+
* Possible failure causes:
|
|
200
|
+
* - `"run_terminated"` - child reached a different terminal state than expected
|
|
201
|
+
* - `"timeout"` - timeout elapsed (only when timeout option provided)
|
|
202
|
+
*
|
|
203
|
+
* @param status - The target terminal status to wait for
|
|
204
|
+
* @param options - Optional configuration with timeout
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* // Wait indefinitely for child to complete
|
|
208
|
+
* const result = await childHandle.waitForStatus("completed");
|
|
209
|
+
* if (result.success) {
|
|
210
|
+
* console.log(result.state.output);
|
|
211
|
+
* } else {
|
|
212
|
+
* console.log(`Child terminated: ${result.cause}`);
|
|
213
|
+
* }
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* // Wait with a timeout
|
|
217
|
+
* const result = await childHandle.waitForStatus("completed", {
|
|
218
|
+
* timeout: { minutes: 5 }
|
|
219
|
+
* });
|
|
220
|
+
* if (!result.success && result.cause === "timeout") {
|
|
221
|
+
* console.log("Child workflow took too long");
|
|
222
|
+
* }
|
|
223
|
+
*/
|
|
224
|
+
waitForStatus<Status extends TerminalWorkflowRunStatus>(status: Status, options?: ChildWorkflowRunWaitOptions<false>): Promise<WorkflowRunWaitResult<Status, Output, false, false>>;
|
|
225
|
+
waitForStatus<Status extends TerminalWorkflowRunStatus>(status: Status, options: ChildWorkflowRunWaitOptions<true>): Promise<WorkflowRunWaitResult<Status, Output, true, false>>;
|
|
226
|
+
};
|
|
227
|
+
interface ChildWorkflowRunWaitOptions<Timed extends boolean> {
|
|
228
|
+
timeout?: Timed extends true ? DurationObject : never;
|
|
229
|
+
}
|
|
230
|
+
|
|
138
231
|
interface WorkflowVersionParams<Input, Output, AppContext, TEventsDefinition extends EventsDefinition> {
|
|
232
|
+
handler: (input: Input, run: Readonly<WorkflowRunContext<Input, AppContext, TEventsDefinition>>, context: AppContext) => Promise<Output>;
|
|
139
233
|
events?: TEventsDefinition;
|
|
140
234
|
opts?: WorkflowOptions;
|
|
141
|
-
handler: (input: Input, run: Readonly<WorkflowRunContext<Input, Output, TEventsDefinition>>, context: AppContext) => Promise<Output>;
|
|
142
235
|
}
|
|
143
236
|
interface WorkflowBuilder<Input, Output, AppContext, TEventsDefinition extends EventsDefinition> {
|
|
144
237
|
opt<Path extends PathFromObject<WorkflowOptions>>(path: Path, value: TypeOfValueAtPath<WorkflowOptions, Path>): WorkflowBuilder<Input, Output, AppContext, TEventsDefinition>;
|
|
145
238
|
start: WorkflowVersion<Input, Output, AppContext, TEventsDefinition>["start"];
|
|
239
|
+
startAsChild: WorkflowVersion<Input, Output, AppContext, TEventsDefinition>["startAsChild"];
|
|
146
240
|
}
|
|
147
241
|
interface WorkflowVersion<Input, Output, AppContext, TEventsDefinition extends EventsDefinition = EventsDefinition> {
|
|
148
242
|
id: WorkflowId;
|
|
149
243
|
versionId: WorkflowVersionId;
|
|
244
|
+
events: EventMulticasters<TEventsDefinition>;
|
|
150
245
|
with(): WorkflowBuilder<Input, Output, AppContext, TEventsDefinition>;
|
|
151
|
-
start: (client: Client<AppContext>, ...args: Input extends null ? [] : [Input]) => Promise<WorkflowRunHandle<Input, Output, TEventsDefinition>>;
|
|
152
|
-
|
|
246
|
+
start: (client: Client<AppContext>, ...args: Input extends null ? [] : [Input]) => Promise<WorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>>;
|
|
247
|
+
startAsChild: <ParentInput, ParentEventsDefinition extends EventsDefinition>(parentRun: WorkflowRunContext<ParentInput, AppContext, ParentEventsDefinition>, ...args: Input extends null ? [] : [Input]) => Promise<ChildWorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>>;
|
|
248
|
+
getHandle: (client: Client<AppContext>, runId: WorkflowRunId) => Promise<WorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>>;
|
|
153
249
|
[INTERNAL]: {
|
|
154
250
|
eventsDefinition: TEventsDefinition;
|
|
155
|
-
handler: (input: Input, run: WorkflowRunContext<Input,
|
|
251
|
+
handler: (input: Input, run: WorkflowRunContext<Input, AppContext, TEventsDefinition>, context: AppContext) => Promise<void>;
|
|
156
252
|
};
|
|
157
253
|
}
|
|
158
254
|
declare class WorkflowVersionImpl<Input, Output, AppContext, TEventsDefinition extends EventsDefinition> implements WorkflowVersion<Input, Output, AppContext, TEventsDefinition> {
|
|
159
255
|
readonly id: WorkflowId;
|
|
160
256
|
readonly versionId: WorkflowVersionId;
|
|
161
257
|
private readonly params;
|
|
258
|
+
readonly events: EventMulticasters<TEventsDefinition>;
|
|
162
259
|
readonly [INTERNAL]: WorkflowVersion<Input, Output, AppContext, TEventsDefinition>[typeof INTERNAL];
|
|
163
260
|
constructor(id: WorkflowId, versionId: WorkflowVersionId, params: WorkflowVersionParams<Input, Output, AppContext, TEventsDefinition>);
|
|
164
261
|
with(): WorkflowBuilder<Input, Output, AppContext, TEventsDefinition>;
|
|
165
|
-
start(client: Client<AppContext>, ...args: Input extends null ? [] : [Input]): Promise<WorkflowRunHandle<Input, Output, TEventsDefinition>>;
|
|
166
|
-
|
|
262
|
+
start(client: Client<AppContext>, ...args: Input extends null ? [] : [Input]): Promise<WorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>>;
|
|
263
|
+
startAsChild<ParentInput>(parentRun: WorkflowRunContext<ParentInput, AppContext, EventsDefinition>, ...args: Input extends null ? [] : [Input]): Promise<ChildWorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>>;
|
|
264
|
+
getHandle(client: Client<AppContext>, runId: WorkflowRunId): Promise<WorkflowRunHandle<Input, Output, AppContext, TEventsDefinition>>;
|
|
167
265
|
private handler;
|
|
168
266
|
private tryExecuteWorkflow;
|
|
169
267
|
private assertRetryAllowed;
|
|
170
268
|
private createFailedState;
|
|
171
269
|
private createAwaitingRetryState;
|
|
270
|
+
private getPath;
|
|
172
271
|
}
|
|
173
272
|
|
|
174
273
|
declare function workflowRegistry(): WorkflowRegistry;
|
|
@@ -186,7 +285,7 @@ interface WorkflowRegistry {
|
|
|
186
285
|
interface SleeperOptions {
|
|
187
286
|
spinThresholdMs: number;
|
|
188
287
|
}
|
|
189
|
-
declare function createSleeper(handle: WorkflowRunHandle<unknown, unknown>, logger: Logger, options: SleeperOptions): (params: SleepParams) => Promise<SleepResult>;
|
|
288
|
+
declare function createSleeper(handle: WorkflowRunHandle<unknown, unknown, unknown>, logger: Logger, options: SleeperOptions): (params: SleepParams) => Promise<SleepResult>;
|
|
190
289
|
|
|
191
290
|
/**
|
|
192
291
|
* Defines a durable workflow with versioning and multiple task execution.
|
|
@@ -241,11 +340,11 @@ interface WorkflowParams {
|
|
|
241
340
|
}
|
|
242
341
|
interface Workflow {
|
|
243
342
|
id: WorkflowId;
|
|
244
|
-
v: <Input extends
|
|
343
|
+
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
344
|
[INTERNAL]: {
|
|
246
345
|
getAllVersions: () => WorkflowVersion<unknown, unknown, unknown>[];
|
|
247
346
|
getVersion: (versionId: WorkflowVersionId) => WorkflowVersion<unknown, unknown, unknown> | undefined;
|
|
248
347
|
};
|
|
249
348
|
}
|
|
250
349
|
|
|
251
|
-
export { type
|
|
350
|
+
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 };
|
package/dist/index.js
CHANGED
|
@@ -77,6 +77,14 @@ function delay(ms, options) {
|
|
|
77
77
|
});
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
// ../../lib/crypto/hash.ts
|
|
81
|
+
async function sha256(input) {
|
|
82
|
+
const data = new TextEncoder().encode(input);
|
|
83
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
|
|
84
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
85
|
+
return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
86
|
+
}
|
|
87
|
+
|
|
80
88
|
// ../../lib/duration/convert.ts
|
|
81
89
|
var MS_PER_SECOND = 1e3;
|
|
82
90
|
var MS_PER_MINUTE = 60 * MS_PER_SECOND;
|
|
@@ -136,6 +144,25 @@ function createSerializableError(error) {
|
|
|
136
144
|
};
|
|
137
145
|
}
|
|
138
146
|
|
|
147
|
+
// ../../lib/json/stable-stringify.ts
|
|
148
|
+
function stableStringify(value) {
|
|
149
|
+
if (value === null || value === void 0) {
|
|
150
|
+
return JSON.stringify(value);
|
|
151
|
+
}
|
|
152
|
+
if (typeof value !== "object") {
|
|
153
|
+
return JSON.stringify(value);
|
|
154
|
+
}
|
|
155
|
+
if (Array.isArray(value)) {
|
|
156
|
+
return `[${value.map((item) => stableStringify(item)).join(",")}]`;
|
|
157
|
+
}
|
|
158
|
+
const keys = Object.keys(value).sort();
|
|
159
|
+
const pairs = keys.map((key) => {
|
|
160
|
+
const val = value[key];
|
|
161
|
+
return `${JSON.stringify(key)}:${stableStringify(val)}`;
|
|
162
|
+
});
|
|
163
|
+
return `{${pairs.join(",")}}`;
|
|
164
|
+
}
|
|
165
|
+
|
|
139
166
|
// ../../lib/object/overrider.ts
|
|
140
167
|
function set(obj, path, value) {
|
|
141
168
|
const keys = path.split(".");
|
|
@@ -279,9 +306,10 @@ function createEventWaiters(handle, eventsDefinition, logger) {
|
|
|
279
306
|
function createEventWaiter(handle, eventId, schema, logger) {
|
|
280
307
|
let nextEventIndex = 0;
|
|
281
308
|
async function wait(options) {
|
|
309
|
+
await handle.refresh();
|
|
282
310
|
const events = handle.run.eventsQueue[eventId]?.events ?? [];
|
|
283
|
-
|
|
284
|
-
|
|
311
|
+
const event2 = events[nextEventIndex];
|
|
312
|
+
if (event2) {
|
|
285
313
|
nextEventIndex++;
|
|
286
314
|
if (event2.status === "timeout") {
|
|
287
315
|
logger.debug("Timed out waiting for event");
|
|
@@ -333,7 +361,8 @@ function createEventSenders(api, workflowRunId, eventsDefinition, logger, onSend
|
|
|
333
361
|
}
|
|
334
362
|
function createEventSender(api, workflowRunId, eventId, schema, logger, onSend) {
|
|
335
363
|
return {
|
|
336
|
-
async send(
|
|
364
|
+
async send(...args) {
|
|
365
|
+
const [data, options] = args;
|
|
337
366
|
if (schema) {
|
|
338
367
|
schema.parse(data);
|
|
339
368
|
}
|
|
@@ -350,35 +379,66 @@ function createEventSender(api, workflowRunId, eventId, schema, logger, onSend)
|
|
|
350
379
|
}
|
|
351
380
|
};
|
|
352
381
|
}
|
|
382
|
+
function createEventMulticasters(eventsDefinition) {
|
|
383
|
+
const senders = {};
|
|
384
|
+
for (const [eventId, eventDefinition] of Object.entries(eventsDefinition)) {
|
|
385
|
+
const sender = createEventMulticaster(eventId, eventDefinition.schema);
|
|
386
|
+
senders[eventId] = sender;
|
|
387
|
+
}
|
|
388
|
+
return senders;
|
|
389
|
+
}
|
|
390
|
+
function createEventMulticaster(eventId, schema) {
|
|
391
|
+
return {
|
|
392
|
+
async send(client, runId, data, options) {
|
|
393
|
+
if (schema) {
|
|
394
|
+
schema.parse(data);
|
|
395
|
+
}
|
|
396
|
+
const runIds = Array.isArray(runId) ? runId : [runId];
|
|
397
|
+
await client.api.workflowRun.multicastEventV1({
|
|
398
|
+
ids: runIds,
|
|
399
|
+
eventId,
|
|
400
|
+
data,
|
|
401
|
+
options
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
}
|
|
353
406
|
|
|
354
407
|
// run/handle.ts
|
|
355
408
|
import { INTERNAL as INTERNAL2 } from "@aikirun/types/symbols";
|
|
356
409
|
import {
|
|
410
|
+
isTerminalWorkflowRunStatus,
|
|
357
411
|
WorkflowRunNotExecutableError
|
|
358
412
|
} from "@aikirun/types/workflow-run";
|
|
359
413
|
async function workflowRunHandle(client, runOrId, eventsDefinition, logger) {
|
|
360
414
|
const run = typeof runOrId !== "string" ? runOrId : (await client.api.workflowRun.getByIdV1({ id: runOrId })).run;
|
|
361
415
|
return new WorkflowRunHandleImpl(
|
|
362
|
-
client
|
|
416
|
+
client,
|
|
363
417
|
run,
|
|
364
418
|
eventsDefinition ?? {},
|
|
365
|
-
logger ?? client.logger.child({
|
|
419
|
+
logger ?? client.logger.child({
|
|
420
|
+
"aiki.workflowId": run.workflowId,
|
|
421
|
+
"aiki.workflowVersionId": run.workflowVersionId,
|
|
422
|
+
"aiki.workflowRunId": run.id
|
|
423
|
+
})
|
|
366
424
|
);
|
|
367
425
|
}
|
|
368
426
|
var WorkflowRunHandleImpl = class {
|
|
369
|
-
constructor(
|
|
370
|
-
this.api = api;
|
|
427
|
+
constructor(client, _run, eventsDefinition, logger) {
|
|
371
428
|
this._run = _run;
|
|
372
429
|
this.logger = logger;
|
|
373
|
-
this.
|
|
430
|
+
this.api = client.api;
|
|
431
|
+
this.events = createEventSenders(client.api, this._run.id, eventsDefinition, this.logger, (run) => {
|
|
374
432
|
this._run = run;
|
|
375
433
|
});
|
|
376
434
|
this[INTERNAL2] = {
|
|
435
|
+
client,
|
|
377
436
|
transitionState: this.transitionState.bind(this),
|
|
378
437
|
transitionTaskState: this.transitionTaskState.bind(this),
|
|
379
438
|
assertExecutionAllowed: this.assertExecutionAllowed.bind(this)
|
|
380
439
|
};
|
|
381
440
|
}
|
|
441
|
+
api;
|
|
382
442
|
events;
|
|
383
443
|
[INTERNAL2];
|
|
384
444
|
get run() {
|
|
@@ -388,59 +448,62 @@ var WorkflowRunHandleImpl = class {
|
|
|
388
448
|
const { run: currentRun } = await this.api.workflowRun.getByIdV1({ id: this.run.id });
|
|
389
449
|
this._run = currentRun;
|
|
390
450
|
}
|
|
391
|
-
// TODO: instead
|
|
392
|
-
// because it is
|
|
451
|
+
// TODO: instead checking the current state, use the transition history
|
|
452
|
+
// because it is possible for a workflow to flash though a state
|
|
393
453
|
// and the handle will never know that the workflow hit that state
|
|
394
|
-
async
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
};
|
|
421
|
-
}
|
|
422
|
-
const maybeResult = await withRetry(
|
|
423
|
-
async () => {
|
|
424
|
-
await this.refresh();
|
|
425
|
-
return this.run.state;
|
|
426
|
-
},
|
|
427
|
-
{ type: "fixed", maxAttempts, delayMs },
|
|
428
|
-
{ shouldRetryOnResult: (state) => Promise.resolve(state.status !== condition.status) }
|
|
429
|
-
).run();
|
|
430
|
-
if (maybeResult.state === "timeout") {
|
|
431
|
-
return { success: false, cause: maybeResult.state };
|
|
432
|
-
}
|
|
454
|
+
async waitForStatus(status, options) {
|
|
455
|
+
return this.waitForStatusByPolling(status, options);
|
|
456
|
+
}
|
|
457
|
+
async waitForStatusByPolling(expectedStatus, options) {
|
|
458
|
+
if (options?.abortSignal?.aborted) {
|
|
459
|
+
return {
|
|
460
|
+
success: false,
|
|
461
|
+
cause: "aborted"
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
const delayMs = options?.interval ? toMilliseconds(options.interval) : 1e3;
|
|
465
|
+
const maxAttempts = options?.timeout ? Math.ceil(toMilliseconds(options.timeout) / delayMs) : Number.POSITIVE_INFINITY;
|
|
466
|
+
const retryStrategy = { type: "fixed", maxAttempts, delayMs };
|
|
467
|
+
const loadState = async () => {
|
|
468
|
+
await this.refresh();
|
|
469
|
+
return this.run.state;
|
|
470
|
+
};
|
|
471
|
+
const isNeitherExpectedNorTerminal = (state) => Promise.resolve(state.status !== expectedStatus && !isTerminalWorkflowRunStatus(state.status));
|
|
472
|
+
if (!Number.isFinite(maxAttempts) && !options?.abortSignal) {
|
|
473
|
+
const maybeResult2 = await withRetry(loadState, retryStrategy, {
|
|
474
|
+
shouldRetryOnResult: isNeitherExpectedNorTerminal
|
|
475
|
+
}).run();
|
|
476
|
+
if (maybeResult2.state === "timeout") {
|
|
477
|
+
throw new Error("Something's wrong, this should've never timed out");
|
|
478
|
+
}
|
|
479
|
+
if (await isNeitherExpectedNorTerminal(maybeResult2.result)) {
|
|
433
480
|
return {
|
|
434
|
-
success:
|
|
435
|
-
|
|
481
|
+
success: false,
|
|
482
|
+
cause: "run_terminated"
|
|
436
483
|
};
|
|
437
484
|
}
|
|
438
|
-
|
|
439
|
-
|
|
485
|
+
return {
|
|
486
|
+
success: true,
|
|
487
|
+
state: maybeResult2.result
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
const maybeResult = options?.abortSignal ? await withRetry(loadState, retryStrategy, {
|
|
491
|
+
abortSignal: options.abortSignal,
|
|
492
|
+
shouldRetryOnResult: isNeitherExpectedNorTerminal
|
|
493
|
+
}).run() : await withRetry(loadState, retryStrategy, { shouldRetryOnResult: isNeitherExpectedNorTerminal }).run();
|
|
494
|
+
if (maybeResult.state === "completed") {
|
|
495
|
+
if (await isNeitherExpectedNorTerminal(maybeResult.result)) {
|
|
496
|
+
return {
|
|
497
|
+
success: false,
|
|
498
|
+
cause: "run_terminated"
|
|
499
|
+
};
|
|
440
500
|
}
|
|
441
|
-
|
|
442
|
-
|
|
501
|
+
return {
|
|
502
|
+
success: true,
|
|
503
|
+
state: maybeResult.result
|
|
504
|
+
};
|
|
443
505
|
}
|
|
506
|
+
return { success: false, cause: maybeResult.state };
|
|
444
507
|
}
|
|
445
508
|
async cancel(reason) {
|
|
446
509
|
return this.transitionState({ status: "cancelled", reason });
|
|
@@ -451,8 +514,11 @@ var WorkflowRunHandleImpl = class {
|
|
|
451
514
|
async resume() {
|
|
452
515
|
return this.transitionState({ status: "scheduled", scheduledInMs: 0, reason: "resume" });
|
|
453
516
|
}
|
|
517
|
+
async awake() {
|
|
518
|
+
return this.transitionState({ status: "scheduled", scheduledInMs: 0, reason: "awake" });
|
|
519
|
+
}
|
|
454
520
|
async transitionState(targetState) {
|
|
455
|
-
if (targetState.status === "scheduled" && (targetState.reason === "new" || targetState.reason === "resume") || targetState.status === "paused" || targetState.status === "cancelled") {
|
|
521
|
+
if (targetState.status === "scheduled" && (targetState.reason === "new" || targetState.reason === "resume" || targetState.reason === "awake") || targetState.status === "paused" || targetState.status === "cancelled") {
|
|
456
522
|
const { run: run2 } = await this.api.workflowRun.transitionStateV1({
|
|
457
523
|
type: "pessimistic",
|
|
458
524
|
id: this.run.id,
|
|
@@ -540,35 +606,121 @@ function createSleeper(handle, logger, options) {
|
|
|
540
606
|
}
|
|
541
607
|
|
|
542
608
|
// workflow.ts
|
|
543
|
-
import { INTERNAL as
|
|
609
|
+
import { INTERNAL as INTERNAL6 } from "@aikirun/types/symbols";
|
|
544
610
|
|
|
545
611
|
// workflow-version.ts
|
|
546
|
-
import { INTERNAL as
|
|
612
|
+
import { INTERNAL as INTERNAL5 } from "@aikirun/types/symbols";
|
|
547
613
|
import { TaskFailedError } from "@aikirun/types/task";
|
|
548
614
|
import {
|
|
549
615
|
WorkflowRunFailedError as WorkflowRunFailedError2,
|
|
616
|
+
WorkflowRunSuspendedError as WorkflowRunSuspendedError4
|
|
617
|
+
} from "@aikirun/types/workflow-run";
|
|
618
|
+
|
|
619
|
+
// run/handle-child.ts
|
|
620
|
+
import { INTERNAL as INTERNAL4 } from "@aikirun/types/symbols";
|
|
621
|
+
import {
|
|
622
|
+
isTerminalWorkflowRunStatus as isTerminalWorkflowRunStatus2,
|
|
550
623
|
WorkflowRunSuspendedError as WorkflowRunSuspendedError3
|
|
551
624
|
} from "@aikirun/types/workflow-run";
|
|
625
|
+
async function childWorkflowRunHandle(client, path, run, parentRun, logger, eventsDefinition) {
|
|
626
|
+
const handle = await workflowRunHandle(client, run, eventsDefinition, logger);
|
|
627
|
+
return {
|
|
628
|
+
run: handle.run,
|
|
629
|
+
events: handle.events,
|
|
630
|
+
refresh: handle.refresh.bind(handle),
|
|
631
|
+
waitForStatus: createStatusWaiter(path, handle, parentRun, logger),
|
|
632
|
+
cancel: handle.cancel.bind(handle),
|
|
633
|
+
pause: handle.pause.bind(handle),
|
|
634
|
+
resume: handle.resume.bind(handle),
|
|
635
|
+
awake: handle.awake.bind(handle),
|
|
636
|
+
[INTERNAL4]: handle[INTERNAL4]
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
function createStatusWaiter(path, handle, parentRun, logger) {
|
|
640
|
+
let nextWaitIndex = 0;
|
|
641
|
+
async function waitForStatus(expectedStatus, options) {
|
|
642
|
+
const parentRunHandle = parentRun[INTERNAL4].handle;
|
|
643
|
+
const waitResults = parentRunHandle.run.childWorkflowRuns[path]?.statusWaitResults ?? [];
|
|
644
|
+
const waitResult = waitResults[nextWaitIndex];
|
|
645
|
+
if (waitResult) {
|
|
646
|
+
nextWaitIndex++;
|
|
647
|
+
if (waitResult.status === "timeout") {
|
|
648
|
+
logger.debug("Timed out waiting for child workflow status", { "aiki.expectedStatus": expectedStatus });
|
|
649
|
+
return {
|
|
650
|
+
success: false,
|
|
651
|
+
cause: "timeout"
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
if (waitResult.childWorkflowRunState.status === expectedStatus) {
|
|
655
|
+
return {
|
|
656
|
+
success: true,
|
|
657
|
+
state: waitResult.childWorkflowRunState
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
if (isTerminalWorkflowRunStatus2(waitResult.childWorkflowRunState.status)) {
|
|
661
|
+
logger.debug("Child workflow run reached termnial state");
|
|
662
|
+
return {
|
|
663
|
+
success: false,
|
|
664
|
+
cause: "run_terminated"
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
const { state } = handle.run;
|
|
669
|
+
if (state.status === expectedStatus) {
|
|
670
|
+
return {
|
|
671
|
+
success: true,
|
|
672
|
+
state
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
if (isTerminalWorkflowRunStatus2(state.status)) {
|
|
676
|
+
logger.debug("Child workflow run reached termnial state");
|
|
677
|
+
return {
|
|
678
|
+
success: false,
|
|
679
|
+
cause: "run_terminated"
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
const timeoutInMs = options?.timeout && toMilliseconds(options.timeout);
|
|
683
|
+
await parentRunHandle[INTERNAL4].transitionState({
|
|
684
|
+
status: "awaiting_child_workflow",
|
|
685
|
+
childWorkflowRunPath: path,
|
|
686
|
+
childWorkflowRunStatus: expectedStatus,
|
|
687
|
+
timeoutInMs
|
|
688
|
+
});
|
|
689
|
+
throw new WorkflowRunSuspendedError3(parentRun.id);
|
|
690
|
+
}
|
|
691
|
+
return waitForStatus;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
// workflow-version.ts
|
|
552
695
|
var WorkflowVersionImpl = class _WorkflowVersionImpl {
|
|
553
696
|
constructor(id, versionId, params) {
|
|
554
697
|
this.id = id;
|
|
555
698
|
this.versionId = versionId;
|
|
556
699
|
this.params = params;
|
|
557
|
-
|
|
558
|
-
|
|
700
|
+
const eventsDefinition = this.params.events ?? {};
|
|
701
|
+
this.events = createEventMulticasters(eventsDefinition);
|
|
702
|
+
this[INTERNAL5] = {
|
|
703
|
+
eventsDefinition,
|
|
559
704
|
handler: this.handler.bind(this)
|
|
560
705
|
};
|
|
561
706
|
}
|
|
562
|
-
|
|
707
|
+
events;
|
|
708
|
+
[INTERNAL5];
|
|
563
709
|
with() {
|
|
564
710
|
const optsOverrider = objectOverrider(this.params.opts ?? {});
|
|
565
|
-
const createBuilder = (optsBuilder) =>
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
client,
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
711
|
+
const createBuilder = (optsBuilder) => {
|
|
712
|
+
return {
|
|
713
|
+
opt: (path, value) => createBuilder(optsBuilder.with(path, value)),
|
|
714
|
+
start: (client, ...args) => new _WorkflowVersionImpl(this.id, this.versionId, {
|
|
715
|
+
...this.params,
|
|
716
|
+
opts: optsBuilder.build()
|
|
717
|
+
}).start(client, ...args),
|
|
718
|
+
startAsChild: (parentRun, ...args) => new _WorkflowVersionImpl(this.id, this.versionId, {
|
|
719
|
+
...this.params,
|
|
720
|
+
opts: optsBuilder.build()
|
|
721
|
+
}).startAsChild(parentRun, ...args)
|
|
722
|
+
};
|
|
723
|
+
};
|
|
572
724
|
return createBuilder(optsOverrider());
|
|
573
725
|
}
|
|
574
726
|
async start(client, ...args) {
|
|
@@ -578,24 +730,73 @@ var WorkflowVersionImpl = class _WorkflowVersionImpl {
|
|
|
578
730
|
input: isNonEmptyArray(args) ? args[0] : null,
|
|
579
731
|
options: this.params.opts
|
|
580
732
|
});
|
|
581
|
-
return workflowRunHandle(client, run, this[
|
|
733
|
+
return workflowRunHandle(client, run, this[INTERNAL5].eventsDefinition);
|
|
734
|
+
}
|
|
735
|
+
async startAsChild(parentRun, ...args) {
|
|
736
|
+
const parentRunHandle = parentRun[INTERNAL5].handle;
|
|
737
|
+
parentRunHandle[INTERNAL5].assertExecutionAllowed();
|
|
738
|
+
const { client } = parentRunHandle[INTERNAL5];
|
|
739
|
+
const input = isNonEmptyArray(args) ? args[0] : null;
|
|
740
|
+
const childRunPath = await this.getPath(input);
|
|
741
|
+
const existingChildRunId = parentRunHandle.run.childWorkflowRuns[childRunPath]?.id;
|
|
742
|
+
if (existingChildRunId) {
|
|
743
|
+
const { run: existingChildRun } = await client.api.workflowRun.getByIdV1({ id: existingChildRunId });
|
|
744
|
+
const logger2 = parentRun.logger.child({
|
|
745
|
+
"aiki.childWorkflowId": existingChildRun.workflowId,
|
|
746
|
+
"aiki.childWorkflowVersionId": existingChildRun.workflowVersionId,
|
|
747
|
+
"aiki.childWorkflowRunId": existingChildRun.id
|
|
748
|
+
});
|
|
749
|
+
return childWorkflowRunHandle(
|
|
750
|
+
client,
|
|
751
|
+
childRunPath,
|
|
752
|
+
existingChildRun,
|
|
753
|
+
parentRun,
|
|
754
|
+
logger2,
|
|
755
|
+
this[INTERNAL5].eventsDefinition
|
|
756
|
+
);
|
|
757
|
+
}
|
|
758
|
+
const { run: newChildRun } = await client.api.workflowRun.createV1({
|
|
759
|
+
workflowId: this.id,
|
|
760
|
+
workflowVersionId: this.versionId,
|
|
761
|
+
input,
|
|
762
|
+
path: childRunPath,
|
|
763
|
+
parentWorkflowRunId: parentRun.id,
|
|
764
|
+
options: {
|
|
765
|
+
...this.params.opts,
|
|
766
|
+
idempotencyKey: childRunPath
|
|
767
|
+
}
|
|
768
|
+
});
|
|
769
|
+
parentRunHandle.run.childWorkflowRuns[childRunPath] = { id: newChildRun.id, statusWaitResults: [] };
|
|
770
|
+
const logger = parentRun.logger.child({
|
|
771
|
+
"aiki.childWorkflowId": newChildRun.workflowId,
|
|
772
|
+
"aiki.childWorkflowVersionId": newChildRun.workflowVersionId,
|
|
773
|
+
"aiki.childWorkflowRunId": newChildRun.id
|
|
774
|
+
});
|
|
775
|
+
return childWorkflowRunHandle(
|
|
776
|
+
client,
|
|
777
|
+
childRunPath,
|
|
778
|
+
newChildRun,
|
|
779
|
+
parentRun,
|
|
780
|
+
logger,
|
|
781
|
+
this[INTERNAL5].eventsDefinition
|
|
782
|
+
);
|
|
582
783
|
}
|
|
583
784
|
async getHandle(client, runId) {
|
|
584
|
-
return workflowRunHandle(client, runId, this[
|
|
785
|
+
return workflowRunHandle(client, runId, this[INTERNAL5].eventsDefinition);
|
|
585
786
|
}
|
|
586
787
|
async handler(input, run, context) {
|
|
587
788
|
const { logger } = run;
|
|
588
|
-
const { handle } = run[
|
|
589
|
-
handle[
|
|
789
|
+
const { handle } = run[INTERNAL5];
|
|
790
|
+
handle[INTERNAL5].assertExecutionAllowed();
|
|
590
791
|
const retryStrategy = this.params.opts?.retry ?? { type: "never" };
|
|
591
792
|
const state = handle.run.state;
|
|
592
793
|
if (state.status === "queued" && state.reason === "retry") {
|
|
593
794
|
await this.assertRetryAllowed(handle, retryStrategy, logger);
|
|
594
795
|
}
|
|
595
796
|
logger.info("Starting workflow");
|
|
596
|
-
await handle[
|
|
797
|
+
await handle[INTERNAL5].transitionState({ status: "running" });
|
|
597
798
|
const output = await this.tryExecuteWorkflow(input, run, context, retryStrategy);
|
|
598
|
-
await handle[
|
|
799
|
+
await handle[INTERNAL5].transitionState({ status: "completed", output });
|
|
599
800
|
logger.info("Workflow complete");
|
|
600
801
|
}
|
|
601
802
|
async tryExecuteWorkflow(input, run, context, retryStrategy) {
|
|
@@ -603,15 +804,15 @@ var WorkflowVersionImpl = class _WorkflowVersionImpl {
|
|
|
603
804
|
try {
|
|
604
805
|
return await this.params.handler(input, run, context);
|
|
605
806
|
} catch (error) {
|
|
606
|
-
if (error instanceof
|
|
807
|
+
if (error instanceof WorkflowRunSuspendedError4 || error instanceof WorkflowRunFailedError2) {
|
|
607
808
|
throw error;
|
|
608
809
|
}
|
|
609
|
-
const { handle } = run[
|
|
810
|
+
const { handle } = run[INTERNAL5];
|
|
610
811
|
const attempts = handle.run.attempts;
|
|
611
812
|
const retryParams = getRetryParams(attempts, retryStrategy);
|
|
612
813
|
if (!retryParams.retriesLeft) {
|
|
613
814
|
const failedState = this.createFailedState(error);
|
|
614
|
-
await handle[
|
|
815
|
+
await handle[INTERNAL5].transitionState(failedState);
|
|
615
816
|
const logMeta2 = {};
|
|
616
817
|
for (const [key, value] of Object.entries(failedState)) {
|
|
617
818
|
logMeta2[`aiki.${key}`] = value;
|
|
@@ -623,7 +824,7 @@ var WorkflowVersionImpl = class _WorkflowVersionImpl {
|
|
|
623
824
|
throw new WorkflowRunFailedError2(run.id, attempts);
|
|
624
825
|
}
|
|
625
826
|
const awaitingRetryState = this.createAwaitingRetryState(error, retryParams.delayMs);
|
|
626
|
-
await handle[
|
|
827
|
+
await handle[INTERNAL5].transitionState(awaitingRetryState);
|
|
627
828
|
const logMeta = {};
|
|
628
829
|
for (const [key, value] of Object.entries(awaitingRetryState)) {
|
|
629
830
|
logMeta[`aiki.${key}`] = value;
|
|
@@ -633,7 +834,7 @@ var WorkflowVersionImpl = class _WorkflowVersionImpl {
|
|
|
633
834
|
"aiki.delayMs": retryParams.delayMs,
|
|
634
835
|
...logMeta
|
|
635
836
|
});
|
|
636
|
-
throw new
|
|
837
|
+
throw new WorkflowRunSuspendedError4(run.id);
|
|
637
838
|
}
|
|
638
839
|
}
|
|
639
840
|
}
|
|
@@ -644,7 +845,7 @@ var WorkflowVersionImpl = class _WorkflowVersionImpl {
|
|
|
644
845
|
logger.error("Workflow retry not allowed", { "aiki.attempts": attempts });
|
|
645
846
|
const error = new WorkflowRunFailedError2(id, attempts);
|
|
646
847
|
const serializableError = createSerializableError(error);
|
|
647
|
-
await handle[
|
|
848
|
+
await handle[INTERNAL5].transitionState({
|
|
648
849
|
status: "failed",
|
|
649
850
|
cause: "self",
|
|
650
851
|
error: serializableError
|
|
@@ -684,6 +885,11 @@ var WorkflowVersionImpl = class _WorkflowVersionImpl {
|
|
|
684
885
|
error: serializableError
|
|
685
886
|
};
|
|
686
887
|
}
|
|
888
|
+
async getPath(input) {
|
|
889
|
+
const inputHash = await sha256(stableStringify(input));
|
|
890
|
+
const path = this.params.opts?.idempotencyKey ? `${this.id}/${this.versionId}/${inputHash}/${this.params.opts.idempotencyKey}` : `${this.id}/${this.versionId}/${inputHash}`;
|
|
891
|
+
return path;
|
|
892
|
+
}
|
|
687
893
|
};
|
|
688
894
|
|
|
689
895
|
// workflow.ts
|
|
@@ -692,11 +898,11 @@ function workflow(params) {
|
|
|
692
898
|
}
|
|
693
899
|
var WorkflowImpl = class {
|
|
694
900
|
id;
|
|
695
|
-
[
|
|
901
|
+
[INTERNAL6];
|
|
696
902
|
workflowVersions = /* @__PURE__ */ new Map();
|
|
697
903
|
constructor(params) {
|
|
698
904
|
this.id = params.id;
|
|
699
|
-
this[
|
|
905
|
+
this[INTERNAL6] = {
|
|
700
906
|
getAllVersions: this.getAllVersions.bind(this),
|
|
701
907
|
getVersion: this.getVersion.bind(this)
|
|
702
908
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aikirun/workflow",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Workflow SDK for Aiki - define durable workflows with tasks, sleeps, waits, and event handling",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"build": "tsup"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@aikirun/types": "0.
|
|
21
|
+
"@aikirun/types": "0.7.0"
|
|
22
22
|
},
|
|
23
23
|
"publishConfig": {
|
|
24
24
|
"access": "public"
|