@aikirun/workflow 0.13.0 → 0.15.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 +17 -0
- package/dist/index.d.ts +78 -48
- package/dist/index.js +101 -43
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -44,6 +44,22 @@ const handle = await onboardingWorkflowV1.start(aikiClient, {
|
|
|
44
44
|
const result = await handle.waitForStatus("completed");
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
+
## Scheduling
|
|
48
|
+
|
|
49
|
+
Run workflows on a schedule using cron expressions or intervals:
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
import { schedule } from "@aikirun/workflow";
|
|
53
|
+
|
|
54
|
+
const dailyReport = schedule({
|
|
55
|
+
name: "daily-report",
|
|
56
|
+
type: "cron",
|
|
57
|
+
expression: "0 9 * * *", // Every day at 9 AM
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
await dailyReport.activate(aikiClient, onboardingWorkflowV1, { email: "daily@example.com" });
|
|
61
|
+
```
|
|
62
|
+
|
|
47
63
|
## Features
|
|
48
64
|
|
|
49
65
|
- **Durable Execution** - Workflows survive crashes and restarts
|
|
@@ -53,6 +69,7 @@ const result = await handle.waitForStatus("completed");
|
|
|
53
69
|
- **Child Workflows** - Compose workflows together
|
|
54
70
|
- **Automatic Retries** - Configurable retry strategies
|
|
55
71
|
- **Versioning** - Run multiple versions simultaneously
|
|
72
|
+
- **Scheduling** - Trigger workflows on cron or interval schedules
|
|
56
73
|
|
|
57
74
|
## Documentation
|
|
58
75
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
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 { WorkflowRun, TerminalWorkflowRunStatus, WorkflowRunState, WorkflowRunId,
|
|
4
|
+
import { WorkflowRun, TerminalWorkflowRunStatus, WorkflowRunState, WorkflowRunId, WorkflowStartOptions, WorkflowDefinitionOptions } from '@aikirun/types/workflow-run';
|
|
5
5
|
import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
6
6
|
import { DurationObject, Duration } from '@aikirun/types/duration';
|
|
7
7
|
import { SleepResult } from '@aikirun/types/sleep';
|
|
@@ -10,6 +10,7 @@ import { Serializable } from '@aikirun/types/serializable';
|
|
|
10
10
|
import { DistributiveOmit, RequireAtLeastOneProp } from '@aikirun/types/utils';
|
|
11
11
|
import { TaskId } from '@aikirun/types/task';
|
|
12
12
|
import { WorkflowRunStateRequest, WorkflowRunTransitionTaskStateRequestV1 } from '@aikirun/types/workflow-run-api';
|
|
13
|
+
import { OverlapPolicy, ScheduleName, ScheduleId } from '@aikirun/types/schedule';
|
|
13
14
|
|
|
14
15
|
type NonEmptyArray<T> = [T, ...T[]];
|
|
15
16
|
|
|
@@ -30,11 +31,11 @@ type PathFromObjectInternal<T, IncludeArrayKeys extends boolean> = And<[
|
|
|
30
31
|
type ExtractObjectType<T> = T extends object ? T : never;
|
|
31
32
|
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;
|
|
32
33
|
|
|
33
|
-
declare function workflowRunHandle<Input, Output, AppContext,
|
|
34
|
-
declare function workflowRunHandle<Input, Output, AppContext,
|
|
35
|
-
interface WorkflowRunHandle<Input, Output, AppContext,
|
|
34
|
+
declare function workflowRunHandle<Input, Output, AppContext, TEvents extends EventsDefinition>(client: Client<AppContext>, id: WorkflowRunId, eventsDefinition?: TEvents, logger?: Logger): Promise<WorkflowRunHandle<Input, Output, AppContext, TEvents>>;
|
|
35
|
+
declare function workflowRunHandle<Input, Output, AppContext, TEvents extends EventsDefinition>(client: Client<AppContext>, run: WorkflowRun<Input, Output>, eventsDefinition?: TEvents, logger?: Logger): Promise<WorkflowRunHandle<Input, Output, AppContext, TEvents>>;
|
|
36
|
+
interface WorkflowRunHandle<Input, Output, AppContext, TEvents extends EventsDefinition = EventsDefinition> {
|
|
36
37
|
run: Readonly<WorkflowRun<Input, Output>>;
|
|
37
|
-
events: EventSenders<
|
|
38
|
+
events: EventSenders<TEvents>;
|
|
38
39
|
refresh: () => Promise<void>;
|
|
39
40
|
/**
|
|
40
41
|
* Waits for the child workflow run to reach a terminal status by polling.
|
|
@@ -145,16 +146,16 @@ interface EventDefinition<Data> {
|
|
|
145
146
|
schema?: StandardSchemaV1<Data>;
|
|
146
147
|
}
|
|
147
148
|
type EventsDefinition = Record<string, EventDefinition<unknown>>;
|
|
148
|
-
type EventData<
|
|
149
|
-
type EventWaiters<
|
|
150
|
-
[K in keyof
|
|
149
|
+
type EventData<TEvent> = TEvent extends EventDefinition<infer Data> ? Data : never;
|
|
150
|
+
type EventWaiters<TEvents extends EventsDefinition> = {
|
|
151
|
+
[K in keyof TEvents]: EventWaiter<EventData<TEvents[K]>>;
|
|
151
152
|
};
|
|
152
153
|
interface EventWaiter<Data> {
|
|
153
154
|
wait(options?: EventWaitOptions<false>): Promise<EventWaitState<Data, false>>;
|
|
154
155
|
wait(options: EventWaitOptions<true>): Promise<EventWaitState<Data, true>>;
|
|
155
156
|
}
|
|
156
|
-
type EventSenders<
|
|
157
|
-
[K in keyof
|
|
157
|
+
type EventSenders<TEvents extends EventsDefinition> = {
|
|
158
|
+
[K in keyof TEvents]: EventSender<EventData<TEvents[K]>>;
|
|
158
159
|
};
|
|
159
160
|
interface EventSender<Data> {
|
|
160
161
|
with(): EventSenderBuilder<Data>;
|
|
@@ -164,8 +165,8 @@ interface EventSenderBuilder<Data> {
|
|
|
164
165
|
opt<Path extends PathFromObject<EventSendOptions>>(path: Path, value: TypeOfValueAtPath<EventSendOptions, Path>): EventSenderBuilder<Data>;
|
|
165
166
|
send: (...args: Data extends void ? [] : [Data]) => Promise<void>;
|
|
166
167
|
}
|
|
167
|
-
type EventMulticasters<
|
|
168
|
-
[K in keyof
|
|
168
|
+
type EventMulticasters<TEvents extends EventsDefinition> = {
|
|
169
|
+
[K in keyof TEvents]: EventMulticaster<EventData<TEvents[K]>>;
|
|
169
170
|
};
|
|
170
171
|
interface EventMulticaster<Data> {
|
|
171
172
|
with(): EventMulticasterBuilder<Data>;
|
|
@@ -175,26 +176,26 @@ interface EventMulticasterBuilder<Data> {
|
|
|
175
176
|
opt<Path extends PathFromObject<EventSendOptions>>(path: Path, value: TypeOfValueAtPath<EventSendOptions, Path>): EventMulticasterBuilder<Data>;
|
|
176
177
|
send: <AppContext>(client: Client<AppContext>, runId: string | string[], ...args: Data extends void ? [] : [Data]) => Promise<void>;
|
|
177
178
|
}
|
|
178
|
-
declare function createEventWaiters<
|
|
179
|
-
declare function createEventSenders<
|
|
179
|
+
declare function createEventWaiters<TEvents extends EventsDefinition>(handle: WorkflowRunHandle<unknown, unknown, unknown, TEvents>, eventsDefinition: TEvents, logger: Logger): EventWaiters<TEvents>;
|
|
180
|
+
declare function createEventSenders<TEvents extends EventsDefinition>(api: ApiClient, workflowRunId: string, eventsDefinition: TEvents, logger: Logger, onSend: (run: WorkflowRun<unknown, unknown>) => void): EventSenders<TEvents>;
|
|
180
181
|
|
|
181
|
-
interface WorkflowRunContext<Input, AppContext,
|
|
182
|
+
interface WorkflowRunContext<Input, AppContext, TEvents extends EventsDefinition> {
|
|
182
183
|
id: WorkflowRunId;
|
|
183
184
|
name: WorkflowName;
|
|
184
185
|
versionId: WorkflowVersionId;
|
|
185
|
-
options:
|
|
186
|
+
options: WorkflowStartOptions;
|
|
186
187
|
logger: Logger;
|
|
187
188
|
sleep: (name: string, duration: Duration) => Promise<SleepResult>;
|
|
188
|
-
events: EventWaiters<
|
|
189
|
+
events: EventWaiters<TEvents>;
|
|
189
190
|
[INTERNAL]: {
|
|
190
|
-
handle: WorkflowRunHandle<Input, unknown, AppContext,
|
|
191
|
+
handle: WorkflowRunHandle<Input, unknown, AppContext, TEvents>;
|
|
191
192
|
options: {
|
|
192
193
|
spinThresholdMs: number;
|
|
193
194
|
};
|
|
194
195
|
};
|
|
195
196
|
}
|
|
196
197
|
|
|
197
|
-
type ChildWorkflowRunHandle<Input, Output, AppContext,
|
|
198
|
+
type ChildWorkflowRunHandle<Input, Output, AppContext, TEvents extends EventsDefinition = EventsDefinition> = Omit<WorkflowRunHandle<Input, Output, AppContext, TEvents>, "waitForStatus"> & {
|
|
198
199
|
/**
|
|
199
200
|
* Waits for the child workflow run to reach a terminal status.
|
|
200
201
|
*
|
|
@@ -239,47 +240,44 @@ interface ChildWorkflowRunWaitOptions<Timed extends boolean> {
|
|
|
239
240
|
timeout?: Timed extends true ? DurationObject : never;
|
|
240
241
|
}
|
|
241
242
|
|
|
242
|
-
interface WorkflowVersionParams<Input, Output, AppContext,
|
|
243
|
-
handler: (run: Readonly<WorkflowRunContext<Input, AppContext,
|
|
244
|
-
events?:
|
|
245
|
-
opts?:
|
|
243
|
+
interface WorkflowVersionParams<Input, Output, AppContext, TEvents extends EventsDefinition> {
|
|
244
|
+
handler: (run: Readonly<WorkflowRunContext<Input, AppContext, TEvents>>, input: Input, context: AppContext) => Promise<Output>;
|
|
245
|
+
events?: TEvents;
|
|
246
|
+
opts?: WorkflowDefinitionOptions;
|
|
246
247
|
schema?: RequireAtLeastOneProp<{
|
|
247
248
|
input?: StandardSchemaV1<Input>;
|
|
248
249
|
output?: StandardSchemaV1<Output>;
|
|
249
250
|
}>;
|
|
250
251
|
}
|
|
251
|
-
interface WorkflowVersion<Input, Output, AppContext,
|
|
252
|
+
interface WorkflowVersion<Input, Output, AppContext, TEvents extends EventsDefinition = EventsDefinition> {
|
|
252
253
|
name: WorkflowName;
|
|
253
254
|
versionId: WorkflowVersionId;
|
|
254
|
-
events: EventMulticasters<
|
|
255
|
-
with(): WorkflowBuilder<Input, Output, AppContext,
|
|
256
|
-
start: (client: Client<AppContext>, ...args: Input extends void ? [] : [Input]) => Promise<WorkflowRunHandle<Input, Output, AppContext,
|
|
257
|
-
startAsChild: <ParentInput,
|
|
258
|
-
getHandleById: (client: Client<AppContext>, runId: string) => Promise<WorkflowRunHandle<Input, Output, AppContext,
|
|
259
|
-
getHandleByReferenceId: (client: Client<AppContext>, referenceId: string) => Promise<WorkflowRunHandle<Input, Output, AppContext,
|
|
255
|
+
events: EventMulticasters<TEvents>;
|
|
256
|
+
with(): WorkflowBuilder<Input, Output, AppContext, TEvents>;
|
|
257
|
+
start: (client: Client<AppContext>, ...args: Input extends void ? [] : [Input]) => Promise<WorkflowRunHandle<Input, Output, AppContext, TEvents>>;
|
|
258
|
+
startAsChild: <ParentInput, ParentEvents extends EventsDefinition>(parentRun: WorkflowRunContext<ParentInput, AppContext, ParentEvents>, ...args: Input extends void ? [] : [Input]) => Promise<ChildWorkflowRunHandle<Input, Output, AppContext, TEvents>>;
|
|
259
|
+
getHandleById: (client: Client<AppContext>, runId: string) => Promise<WorkflowRunHandle<Input, Output, AppContext, TEvents>>;
|
|
260
|
+
getHandleByReferenceId: (client: Client<AppContext>, referenceId: string) => Promise<WorkflowRunHandle<Input, Output, AppContext, TEvents>>;
|
|
260
261
|
[INTERNAL]: {
|
|
261
|
-
eventsDefinition:
|
|
262
|
-
handler: (run: WorkflowRunContext<Input, AppContext,
|
|
262
|
+
eventsDefinition: TEvents;
|
|
263
|
+
handler: (run: WorkflowRunContext<Input, AppContext, TEvents>, input: Input, context: AppContext) => Promise<void>;
|
|
263
264
|
};
|
|
264
265
|
}
|
|
265
|
-
|
|
266
|
-
opt<Path extends PathFromObject<WorkflowOptions>>(path: Path, value: TypeOfValueAtPath<WorkflowOptions, Path>): WorkflowBuilder<Input, Output, AppContext, TEventsDefinition>;
|
|
267
|
-
start: WorkflowVersion<Input, Output, AppContext, TEventsDefinition>["start"];
|
|
268
|
-
startAsChild: WorkflowVersion<Input, Output, AppContext, TEventsDefinition>["startAsChild"];
|
|
269
|
-
}
|
|
270
|
-
declare class WorkflowVersionImpl<Input, Output, AppContext, TEventsDefinition extends EventsDefinition> implements WorkflowVersion<Input, Output, AppContext, TEventsDefinition> {
|
|
266
|
+
declare class WorkflowVersionImpl<Input, Output, AppContext, TEvents extends EventsDefinition> implements WorkflowVersion<Input, Output, AppContext, TEvents> {
|
|
271
267
|
readonly name: WorkflowName;
|
|
272
268
|
readonly versionId: WorkflowVersionId;
|
|
273
269
|
private readonly params;
|
|
274
|
-
readonly events: EventMulticasters<
|
|
275
|
-
readonly [INTERNAL]: WorkflowVersion<Input, Output, AppContext,
|
|
276
|
-
constructor(name: WorkflowName, versionId: WorkflowVersionId, params: WorkflowVersionParams<Input, Output, AppContext,
|
|
277
|
-
with(): WorkflowBuilder<Input, Output, AppContext,
|
|
278
|
-
start(client: Client<AppContext>, ...args: Input extends void ? [] : [Input]): Promise<WorkflowRunHandle<Input, Output, AppContext,
|
|
279
|
-
|
|
270
|
+
readonly events: EventMulticasters<TEvents>;
|
|
271
|
+
readonly [INTERNAL]: WorkflowVersion<Input, Output, AppContext, TEvents>[typeof INTERNAL];
|
|
272
|
+
constructor(name: WorkflowName, versionId: WorkflowVersionId, params: WorkflowVersionParams<Input, Output, AppContext, TEvents>);
|
|
273
|
+
with(): WorkflowBuilder<Input, Output, AppContext, TEvents>;
|
|
274
|
+
start(client: Client<AppContext>, ...args: Input extends void ? [] : [Input]): Promise<WorkflowRunHandle<Input, Output, AppContext, TEvents>>;
|
|
275
|
+
startWithOpts(client: Client<AppContext>, startOpts: WorkflowStartOptions, ...args: Input extends void ? [] : [Input]): Promise<WorkflowRunHandle<Input, Output, AppContext, TEvents>>;
|
|
276
|
+
startAsChild(parentRun: WorkflowRunContext<unknown, AppContext, EventsDefinition>, ...args: Input extends void ? [] : [Input]): Promise<ChildWorkflowRunHandle<Input, Output, AppContext, TEvents>>;
|
|
277
|
+
startAsChildWithOpts(parentRun: WorkflowRunContext<unknown, AppContext, EventsDefinition>, startOpts: WorkflowStartOptions, ...args: Input extends void ? [] : [Input]): Promise<ChildWorkflowRunHandle<Input, Output, AppContext, TEvents>>;
|
|
280
278
|
private assertUniqueChildRunReferenceId;
|
|
281
|
-
getHandleById(client: Client<AppContext>, runId: string): Promise<WorkflowRunHandle<Input, Output, AppContext,
|
|
282
|
-
getHandleByReferenceId(client: Client<AppContext>, referenceId: string): Promise<WorkflowRunHandle<Input, Output, AppContext,
|
|
279
|
+
getHandleById(client: Client<AppContext>, runId: string): Promise<WorkflowRunHandle<Input, Output, AppContext, TEvents>>;
|
|
280
|
+
getHandleByReferenceId(client: Client<AppContext>, referenceId: string): Promise<WorkflowRunHandle<Input, Output, AppContext, TEvents>>;
|
|
283
281
|
private handler;
|
|
284
282
|
private tryExecuteWorkflow;
|
|
285
283
|
private assertRetryAllowed;
|
|
@@ -287,6 +285,11 @@ declare class WorkflowVersionImpl<Input, Output, AppContext, TEventsDefinition e
|
|
|
287
285
|
private createFailedState;
|
|
288
286
|
private createAwaitingRetryState;
|
|
289
287
|
}
|
|
288
|
+
interface WorkflowBuilder<Input, Output, AppContext, TEvents extends EventsDefinition> {
|
|
289
|
+
opt<Path extends PathFromObject<WorkflowStartOptions>>(path: Path, value: TypeOfValueAtPath<WorkflowStartOptions, Path>): WorkflowBuilder<Input, Output, AppContext, TEvents>;
|
|
290
|
+
start: WorkflowVersion<Input, Output, AppContext, TEvents>["start"];
|
|
291
|
+
startAsChild: WorkflowVersion<Input, Output, AppContext, TEvents>["startAsChild"];
|
|
292
|
+
}
|
|
290
293
|
|
|
291
294
|
declare function workflowRegistry(): WorkflowRegistry;
|
|
292
295
|
type Workflow$1 = WorkflowVersion<unknown, unknown, unknown>;
|
|
@@ -302,6 +305,33 @@ interface WorkflowRegistry {
|
|
|
302
305
|
|
|
303
306
|
declare function createSleeper(handle: WorkflowRunHandle<unknown, unknown, unknown>, logger: Logger): (name: string, duration: Duration) => Promise<SleepResult>;
|
|
304
307
|
|
|
308
|
+
interface CronScheduleParams {
|
|
309
|
+
type: "cron";
|
|
310
|
+
expression: string;
|
|
311
|
+
timezone?: string;
|
|
312
|
+
overlapPolicy?: OverlapPolicy;
|
|
313
|
+
}
|
|
314
|
+
interface IntervalScheduleParams {
|
|
315
|
+
type: "interval";
|
|
316
|
+
every: DurationObject;
|
|
317
|
+
overlapPolicy?: OverlapPolicy;
|
|
318
|
+
}
|
|
319
|
+
type ScheduleParams = CronScheduleParams | IntervalScheduleParams;
|
|
320
|
+
interface ScheduleHandle {
|
|
321
|
+
id: ScheduleId;
|
|
322
|
+
name: ScheduleName;
|
|
323
|
+
pause(): Promise<void>;
|
|
324
|
+
resume(): Promise<void>;
|
|
325
|
+
delete(): Promise<void>;
|
|
326
|
+
}
|
|
327
|
+
type ScheduleDefinition = ScheduleParams & {
|
|
328
|
+
name: ScheduleName;
|
|
329
|
+
activate<Input, Output, AppContext, TEvents extends EventsDefinition>(client: Client<AppContext>, workflow: WorkflowVersion<Input, Output, AppContext, TEvents>, ...args: Input extends void ? [] : [Input]): Promise<ScheduleHandle>;
|
|
330
|
+
};
|
|
331
|
+
declare function schedule(params: {
|
|
332
|
+
name: string;
|
|
333
|
+
} & ScheduleParams): ScheduleDefinition;
|
|
334
|
+
|
|
305
335
|
/**
|
|
306
336
|
* Defines a durable workflow with versioning and multiple task execution.
|
|
307
337
|
*
|
|
@@ -355,11 +385,11 @@ interface WorkflowParams {
|
|
|
355
385
|
}
|
|
356
386
|
interface Workflow {
|
|
357
387
|
name: WorkflowName;
|
|
358
|
-
v: <Input extends Serializable, Output extends Serializable, AppContext = null,
|
|
388
|
+
v: <Input extends Serializable, Output extends Serializable, AppContext = null, TEvents extends EventsDefinition = Record<string, never>>(versionId: string, params: WorkflowVersionParams<Input, Output, AppContext, TEvents>) => WorkflowVersion<Input, Output, AppContext, TEvents>;
|
|
359
389
|
[INTERNAL]: {
|
|
360
390
|
getAllVersions: () => WorkflowVersion<unknown, unknown, unknown>[];
|
|
361
391
|
getVersion: (versionId: WorkflowVersionId) => WorkflowVersion<unknown, unknown, unknown> | undefined;
|
|
362
392
|
};
|
|
363
393
|
}
|
|
364
394
|
|
|
365
|
-
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 };
|
|
395
|
+
export { type EventMulticaster, type EventMulticasters, type EventSender, type EventSenders, type EventWaiter, type EventWaiters, type ScheduleDefinition, type ScheduleHandle, type ScheduleParams, type Workflow, type WorkflowParams, type WorkflowRegistry, type WorkflowRunContext, type WorkflowRunHandle, type WorkflowRunWaitOptions, type WorkflowVersion, WorkflowVersionImpl, type WorkflowVersionParams, createEventSenders, createEventWaiters, createSleeper, event, schedule, workflow, workflowRegistry, workflowRunHandle };
|
package/dist/index.js
CHANGED
|
@@ -392,10 +392,9 @@ function createEventSender(api, workflowRunId, eventName, schema, logger, onSend
|
|
|
392
392
|
send: (...args) => createEventSender(api, workflowRunId, eventName, schema, logger, onSend, optsBuilder.build()).send(...args)
|
|
393
393
|
});
|
|
394
394
|
async function send(...args) {
|
|
395
|
-
|
|
396
|
-
let data = dataRaw;
|
|
395
|
+
let data = args[0];
|
|
397
396
|
if (schema) {
|
|
398
|
-
const schemaValidation = schema["~standard"].validate(
|
|
397
|
+
const schemaValidation = schema["~standard"].validate(data);
|
|
399
398
|
const schemaValidationResult = schemaValidation instanceof Promise ? await schemaValidation : schemaValidation;
|
|
400
399
|
if (schemaValidationResult.issues) {
|
|
401
400
|
logger.error("Invalid event data", { "aiki.issues": schemaValidationResult.issues });
|
|
@@ -443,10 +442,9 @@ function createEventMulticaster(workflowName, workflowVersionId, eventName, sche
|
|
|
443
442
|
)
|
|
444
443
|
});
|
|
445
444
|
async function send(client, runId, ...args) {
|
|
446
|
-
|
|
447
|
-
let data = dataRaw;
|
|
445
|
+
let data = args[0];
|
|
448
446
|
if (schema) {
|
|
449
|
-
const schemaValidation = schema["~standard"].validate(
|
|
447
|
+
const schemaValidation = schema["~standard"].validate(data);
|
|
450
448
|
const schemaValidationResult = schemaValidation instanceof Promise ? await schemaValidation : schemaValidation;
|
|
451
449
|
if (schemaValidationResult.issues) {
|
|
452
450
|
client.logger.error("Invalid event data", {
|
|
@@ -548,15 +546,15 @@ var WorkflowRunHandleImpl = class {
|
|
|
548
546
|
await this.refresh();
|
|
549
547
|
return this.run.state;
|
|
550
548
|
};
|
|
551
|
-
const isNeitherExpectedNorTerminal = (state) =>
|
|
549
|
+
const isNeitherExpectedNorTerminal = (state) => state.status !== expectedStatus && !isTerminalWorkflowRunStatus(state.status);
|
|
552
550
|
if (!Number.isFinite(maxAttempts) && !options?.abortSignal) {
|
|
553
551
|
const maybeResult2 = await withRetry(loadState, retryStrategy, {
|
|
554
|
-
shouldRetryOnResult: isNeitherExpectedNorTerminal
|
|
552
|
+
shouldRetryOnResult: async (state) => isNeitherExpectedNorTerminal(state)
|
|
555
553
|
}).run();
|
|
556
554
|
if (maybeResult2.state === "timeout") {
|
|
557
555
|
throw new Error("Something's wrong, this should've never timed out");
|
|
558
556
|
}
|
|
559
|
-
if (
|
|
557
|
+
if (maybeResult2.result.status !== expectedStatus) {
|
|
560
558
|
return {
|
|
561
559
|
success: false,
|
|
562
560
|
cause: "run_terminated"
|
|
@@ -569,10 +567,13 @@ var WorkflowRunHandleImpl = class {
|
|
|
569
567
|
}
|
|
570
568
|
const maybeResult = options?.abortSignal ? await withRetry(loadState, retryStrategy, {
|
|
571
569
|
abortSignal: options.abortSignal,
|
|
572
|
-
shouldRetryOnResult: isNeitherExpectedNorTerminal
|
|
573
|
-
}).run() : await withRetry(loadState, retryStrategy, {
|
|
570
|
+
shouldRetryOnResult: async (state) => isNeitherExpectedNorTerminal(state)
|
|
571
|
+
}).run() : await withRetry(loadState, retryStrategy, {
|
|
572
|
+
shouldRetryOnResult: async (state) => isNeitherExpectedNorTerminal(state)
|
|
573
|
+
}).run();
|
|
574
|
+
this.logger.info("Maybe result", { maybeResult });
|
|
574
575
|
if (maybeResult.state === "completed") {
|
|
575
|
-
if (
|
|
576
|
+
if (maybeResult.result.status !== expectedStatus) {
|
|
576
577
|
return {
|
|
577
578
|
success: false,
|
|
578
579
|
cause: "run_terminated"
|
|
@@ -734,11 +735,59 @@ function createSleeper(handle, logger) {
|
|
|
734
735
|
};
|
|
735
736
|
}
|
|
736
737
|
|
|
738
|
+
// schedule.ts
|
|
739
|
+
function schedule(params) {
|
|
740
|
+
const { name, ...scheduleParams } = params;
|
|
741
|
+
return {
|
|
742
|
+
name,
|
|
743
|
+
...scheduleParams,
|
|
744
|
+
async activate(client, workflow2, ...args) {
|
|
745
|
+
const input = args[0];
|
|
746
|
+
let scheduleSpec;
|
|
747
|
+
if (scheduleParams.type === "interval") {
|
|
748
|
+
const { every, ...rest } = scheduleParams;
|
|
749
|
+
scheduleSpec = {
|
|
750
|
+
...rest,
|
|
751
|
+
everyMs: toMilliseconds(every)
|
|
752
|
+
};
|
|
753
|
+
} else {
|
|
754
|
+
scheduleSpec = scheduleParams;
|
|
755
|
+
}
|
|
756
|
+
const { schedule: schedule2 } = await client.api.schedule.activateV1({
|
|
757
|
+
name,
|
|
758
|
+
workflowName: workflow2.name,
|
|
759
|
+
workflowVersionId: workflow2.versionId,
|
|
760
|
+
spec: scheduleSpec,
|
|
761
|
+
input
|
|
762
|
+
});
|
|
763
|
+
client.logger.info("Schedule activated", {
|
|
764
|
+
scheduleSpec,
|
|
765
|
+
workflowName: workflow2.name,
|
|
766
|
+
workflowVersionId: workflow2.versionId
|
|
767
|
+
});
|
|
768
|
+
const scheduleId = schedule2.id;
|
|
769
|
+
return {
|
|
770
|
+
id: scheduleId,
|
|
771
|
+
name,
|
|
772
|
+
pause: async () => {
|
|
773
|
+
await client.api.schedule.pauseV1({ id: scheduleId });
|
|
774
|
+
},
|
|
775
|
+
resume: async () => {
|
|
776
|
+
await client.api.schedule.resumeV1({ id: scheduleId });
|
|
777
|
+
},
|
|
778
|
+
delete: async () => {
|
|
779
|
+
await client.api.schedule.deleteV1({ id: scheduleId });
|
|
780
|
+
}
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
};
|
|
784
|
+
}
|
|
785
|
+
|
|
737
786
|
// workflow.ts
|
|
738
787
|
import { INTERNAL as INTERNAL6 } from "@aikirun/types/symbols";
|
|
739
788
|
|
|
740
|
-
// ../../lib/
|
|
741
|
-
function
|
|
789
|
+
// ../../lib/address/index.ts
|
|
790
|
+
function getWorkflowRunAddress(name, versionId, referenceId) {
|
|
742
791
|
return `${name}/${versionId}/${referenceId}`;
|
|
743
792
|
}
|
|
744
793
|
|
|
@@ -777,7 +826,7 @@ function createStatusWaiter(handle, parentRun, logger) {
|
|
|
777
826
|
let nextWaitIndex = 0;
|
|
778
827
|
async function waitForStatus(expectedStatus, options) {
|
|
779
828
|
const parentRunHandle = parentRun[INTERNAL4].handle;
|
|
780
|
-
const waitResults = parentRunHandle.run.childWorkflowRuns[handle.run.
|
|
829
|
+
const waitResults = parentRunHandle.run.childWorkflowRuns[handle.run.address]?.statusWaitResults ?? [];
|
|
781
830
|
const waitResult = waitResults[nextWaitIndex];
|
|
782
831
|
if (waitResult) {
|
|
783
832
|
nextWaitIndex++;
|
|
@@ -846,7 +895,7 @@ function createStatusWaiter(handle, parentRun, logger) {
|
|
|
846
895
|
}
|
|
847
896
|
|
|
848
897
|
// workflow-version.ts
|
|
849
|
-
var WorkflowVersionImpl = class
|
|
898
|
+
var WorkflowVersionImpl = class {
|
|
850
899
|
constructor(name, versionId, params) {
|
|
851
900
|
this.name = name;
|
|
852
901
|
this.versionId = versionId;
|
|
@@ -861,28 +910,18 @@ var WorkflowVersionImpl = class _WorkflowVersionImpl {
|
|
|
861
910
|
events;
|
|
862
911
|
[INTERNAL5];
|
|
863
912
|
with() {
|
|
864
|
-
const
|
|
865
|
-
const
|
|
866
|
-
|
|
867
|
-
opt: (path, value) => createBuilder(optsBuilder.with(path, value)),
|
|
868
|
-
start: (client, ...args) => new _WorkflowVersionImpl(this.name, this.versionId, {
|
|
869
|
-
...this.params,
|
|
870
|
-
opts: optsBuilder.build()
|
|
871
|
-
}).start(client, ...args),
|
|
872
|
-
startAsChild: (parentRun, ...args) => new _WorkflowVersionImpl(this.name, this.versionId, {
|
|
873
|
-
...this.params,
|
|
874
|
-
opts: optsBuilder.build()
|
|
875
|
-
}).startAsChild(parentRun, ...args)
|
|
876
|
-
};
|
|
877
|
-
};
|
|
878
|
-
return createBuilder(optsOverrider());
|
|
913
|
+
const startOpts = this.params.opts ?? {};
|
|
914
|
+
const startOptsOverrider = objectOverrider(startOpts);
|
|
915
|
+
return new WorkflowBuilderImpl(this, startOptsOverrider());
|
|
879
916
|
}
|
|
880
917
|
async start(client, ...args) {
|
|
881
|
-
|
|
882
|
-
|
|
918
|
+
return this.startWithOpts(client, this.params.opts ?? {}, ...args);
|
|
919
|
+
}
|
|
920
|
+
async startWithOpts(client, startOpts, ...args) {
|
|
921
|
+
let input = args[0];
|
|
883
922
|
const schema = this.params.schema?.input;
|
|
884
923
|
if (schema) {
|
|
885
|
-
const schemaValidation = schema["~standard"].validate(
|
|
924
|
+
const schemaValidation = schema["~standard"].validate(input);
|
|
886
925
|
const schemaValidationResult = schemaValidation instanceof Promise ? await schemaValidation : schemaValidation;
|
|
887
926
|
if (schemaValidationResult.issues) {
|
|
888
927
|
client.logger.error("Invalid workflow data", { "aiki.issues": schemaValidationResult.issues });
|
|
@@ -894,7 +933,7 @@ var WorkflowVersionImpl = class _WorkflowVersionImpl {
|
|
|
894
933
|
name: this.name,
|
|
895
934
|
versionId: this.versionId,
|
|
896
935
|
input,
|
|
897
|
-
options:
|
|
936
|
+
options: startOpts
|
|
898
937
|
});
|
|
899
938
|
client.logger.info("Created workflow", {
|
|
900
939
|
"aiki.workflowName": this.name,
|
|
@@ -904,15 +943,18 @@ var WorkflowVersionImpl = class _WorkflowVersionImpl {
|
|
|
904
943
|
return workflowRunHandle(client, run, this[INTERNAL5].eventsDefinition);
|
|
905
944
|
}
|
|
906
945
|
async startAsChild(parentRun, ...args) {
|
|
946
|
+
return this.startAsChildWithOpts(parentRun, this.params.opts ?? {}, ...args);
|
|
947
|
+
}
|
|
948
|
+
async startAsChildWithOpts(parentRun, startOpts, ...args) {
|
|
907
949
|
const parentRunHandle = parentRun[INTERNAL5].handle;
|
|
908
950
|
parentRunHandle[INTERNAL5].assertExecutionAllowed();
|
|
909
951
|
const { client } = parentRunHandle[INTERNAL5];
|
|
910
|
-
const inputRaw =
|
|
952
|
+
const inputRaw = args[0];
|
|
911
953
|
const input = await this.parse(parentRunHandle, this.params.schema?.input, inputRaw, parentRun.logger);
|
|
912
954
|
const inputHash = await hashInput(input);
|
|
913
|
-
const reference =
|
|
914
|
-
const
|
|
915
|
-
const existingRunInfo = parentRunHandle.run.childWorkflowRuns[
|
|
955
|
+
const reference = startOpts.reference;
|
|
956
|
+
const address = getWorkflowRunAddress(this.name, this.versionId, reference?.id ?? inputHash);
|
|
957
|
+
const existingRunInfo = parentRunHandle.run.childWorkflowRuns[address];
|
|
916
958
|
if (existingRunInfo) {
|
|
917
959
|
await this.assertUniqueChildRunReferenceId(
|
|
918
960
|
parentRunHandle,
|
|
@@ -943,9 +985,9 @@ var WorkflowVersionImpl = class _WorkflowVersionImpl {
|
|
|
943
985
|
versionId: this.versionId,
|
|
944
986
|
input,
|
|
945
987
|
parentWorkflowRunId: parentRun.id,
|
|
946
|
-
options:
|
|
988
|
+
options: startOpts
|
|
947
989
|
});
|
|
948
|
-
parentRunHandle.run.childWorkflowRuns[
|
|
990
|
+
parentRunHandle.run.childWorkflowRuns[address] = {
|
|
949
991
|
id: newRun.id,
|
|
950
992
|
name: newRun.name,
|
|
951
993
|
versionId: newRun.versionId,
|
|
@@ -968,8 +1010,8 @@ var WorkflowVersionImpl = class _WorkflowVersionImpl {
|
|
|
968
1010
|
}
|
|
969
1011
|
async assertUniqueChildRunReferenceId(parentRunHandle, existingRunInfo, inputHash, reference, logger) {
|
|
970
1012
|
if (existingRunInfo.inputHash !== inputHash && reference) {
|
|
971
|
-
const
|
|
972
|
-
if (
|
|
1013
|
+
const conflictPolicy = reference.conflictPolicy ?? "error";
|
|
1014
|
+
if (conflictPolicy !== "error") {
|
|
973
1015
|
return;
|
|
974
1016
|
}
|
|
975
1017
|
logger.error("Reference ID already used by another child workflow", {
|
|
@@ -1120,6 +1162,21 @@ var WorkflowVersionImpl = class _WorkflowVersionImpl {
|
|
|
1120
1162
|
};
|
|
1121
1163
|
}
|
|
1122
1164
|
};
|
|
1165
|
+
var WorkflowBuilderImpl = class _WorkflowBuilderImpl {
|
|
1166
|
+
constructor(workflow2, startOptsBuilder) {
|
|
1167
|
+
this.workflow = workflow2;
|
|
1168
|
+
this.startOptsBuilder = startOptsBuilder;
|
|
1169
|
+
}
|
|
1170
|
+
opt(path, value) {
|
|
1171
|
+
return new _WorkflowBuilderImpl(this.workflow, this.startOptsBuilder.with(path, value));
|
|
1172
|
+
}
|
|
1173
|
+
start(client, ...args) {
|
|
1174
|
+
return this.workflow.startWithOpts(client, this.startOptsBuilder.build(), ...args);
|
|
1175
|
+
}
|
|
1176
|
+
startAsChild(parentRun, ...args) {
|
|
1177
|
+
return this.workflow.startAsChildWithOpts(parentRun, this.startOptsBuilder.build(), ...args);
|
|
1178
|
+
}
|
|
1179
|
+
};
|
|
1123
1180
|
|
|
1124
1181
|
// workflow.ts
|
|
1125
1182
|
function workflow(params) {
|
|
@@ -1160,6 +1217,7 @@ export {
|
|
|
1160
1217
|
createEventWaiters,
|
|
1161
1218
|
createSleeper,
|
|
1162
1219
|
event,
|
|
1220
|
+
schedule,
|
|
1163
1221
|
workflow,
|
|
1164
1222
|
workflowRegistry,
|
|
1165
1223
|
workflowRunHandle
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aikirun/workflow",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.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.15.0",
|
|
22
22
|
"@standard-schema/spec": "^1.1.0"
|
|
23
23
|
},
|
|
24
24
|
"publishConfig": {
|