@aikirun/task 0.23.1 → 0.24.1
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 +28 -10
- package/dist/index.js +21 -24
- package/package.json +2 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
import { DistributiveOmit, RequireAtLeastOneProp } from '@aikirun/types/property';
|
|
1
2
|
import { Serializable } from '@aikirun/types/serializable';
|
|
2
|
-
import { TaskName, TaskStartOptions, TaskDefinitionOptions } from '@aikirun/types/task';
|
|
3
|
-
import { WorkflowRunContext } from '@aikirun/workflow';
|
|
3
|
+
import { TaskInfo, TaskName, TaskStartOptions, TaskDefinitionOptions } from '@aikirun/types/task';
|
|
4
4
|
import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
5
|
-
import {
|
|
5
|
+
import { Logger } from '@aikirun/types/logger';
|
|
6
|
+
import { ReplayManifest } from '@aikirun/types/replay-manifest';
|
|
7
|
+
import { INTERNAL } from '@aikirun/types/symbols';
|
|
8
|
+
import { WorkflowRunId, WorkflowRun } from '@aikirun/types/workflow-run';
|
|
9
|
+
import { WorkflowRunStateRequest, WorkflowRunTransitionTaskStateRequestV1 } from '@aikirun/types/workflow-run-api';
|
|
6
10
|
|
|
7
11
|
type NonEmptyArray<T> = [T, ...T[]];
|
|
8
12
|
|
|
@@ -20,11 +24,25 @@ type PathFromObjectInternal<T, IncludeArrayKeys extends boolean> = And<[IsSubtyp
|
|
|
20
24
|
type ExtractObjectType<T> = T extends object ? T : never;
|
|
21
25
|
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;
|
|
22
26
|
|
|
23
|
-
interface
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
interface WorkflowRunContext {
|
|
28
|
+
id: WorkflowRunId;
|
|
29
|
+
logger: Logger;
|
|
30
|
+
[INTERNAL]: {
|
|
31
|
+
handle: WorkflowRunHandle;
|
|
32
|
+
replayManifest: ReplayManifest;
|
|
33
|
+
options: {
|
|
34
|
+
spinThresholdMs: number;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
interface WorkflowRunHandle {
|
|
39
|
+
run: Readonly<WorkflowRun>;
|
|
40
|
+
[INTERNAL]: {
|
|
41
|
+
transitionState: (state: WorkflowRunStateRequest) => Promise<void>;
|
|
42
|
+
transitionTaskState: (request: DistributiveOmit<WorkflowRunTransitionTaskStateRequestV1, "id" | "expectedWorkflowRunRevision">) => Promise<TaskInfo>;
|
|
43
|
+
assertExecutionAllowed: () => void;
|
|
44
|
+
};
|
|
26
45
|
}
|
|
27
|
-
type EventsDefinition = Record<string, EventDefinition<unknown>>;
|
|
28
46
|
|
|
29
47
|
/**
|
|
30
48
|
* Defines a durable task with deterministic execution and automatic retries.
|
|
@@ -56,7 +74,7 @@ type EventsDefinition = Record<string, EventDefinition<unknown>>;
|
|
|
56
74
|
* handler(input: { cardId: string; amount: number }) {
|
|
57
75
|
* return paymentService.charge(input.cardId, input.amount);
|
|
58
76
|
* },
|
|
59
|
-
*
|
|
77
|
+
* options: {
|
|
60
78
|
* retry: {
|
|
61
79
|
* type: "fixed",
|
|
62
80
|
* maxAttempts: 3,
|
|
@@ -73,7 +91,7 @@ declare function task<Input extends Serializable, Output extends Serializable>(p
|
|
|
73
91
|
interface TaskParams<Input, Output> {
|
|
74
92
|
name: string;
|
|
75
93
|
handler: (input: Input) => Promise<Output>;
|
|
76
|
-
|
|
94
|
+
options?: TaskDefinitionOptions;
|
|
77
95
|
schema?: RequireAtLeastOneProp<{
|
|
78
96
|
input?: StandardSchemaV1<Input>;
|
|
79
97
|
output?: StandardSchemaV1<Output>;
|
|
@@ -82,7 +100,7 @@ interface TaskParams<Input, Output> {
|
|
|
82
100
|
interface Task<Input, Output> {
|
|
83
101
|
name: TaskName;
|
|
84
102
|
with(): TaskBuilder<Input, Output>;
|
|
85
|
-
start: (run: WorkflowRunContext
|
|
103
|
+
start: (run: WorkflowRunContext, ...args: Input extends void ? [] : [Input]) => Promise<Output>;
|
|
86
104
|
}
|
|
87
105
|
interface TaskBuilder<Input, Output> {
|
|
88
106
|
opt<Path extends PathFromObject<TaskStartOptions>>(path: Path, value: TypeOfValueAtPath<TaskStartOptions, Path>): TaskBuilder<Input, Output>;
|
package/dist/index.js
CHANGED
|
@@ -154,13 +154,13 @@ function getRetryParams(attempts, strategy) {
|
|
|
154
154
|
|
|
155
155
|
// task.ts
|
|
156
156
|
import { INTERNAL } from "@aikirun/types/symbols";
|
|
157
|
-
import { TaskFailedError } from "@aikirun/types/task";
|
|
157
|
+
import { TaskFailedError } from "@aikirun/types/task-error";
|
|
158
158
|
import {
|
|
159
159
|
NonDeterminismError,
|
|
160
160
|
WorkflowRunFailedError,
|
|
161
161
|
WorkflowRunRevisionConflictError,
|
|
162
162
|
WorkflowRunSuspendedError
|
|
163
|
-
} from "@aikirun/types/workflow-run";
|
|
163
|
+
} from "@aikirun/types/workflow-run-error";
|
|
164
164
|
function task(params) {
|
|
165
165
|
return new TaskImpl(params);
|
|
166
166
|
}
|
|
@@ -171,14 +171,14 @@ var TaskImpl = class {
|
|
|
171
171
|
}
|
|
172
172
|
name;
|
|
173
173
|
with() {
|
|
174
|
-
const
|
|
175
|
-
const
|
|
176
|
-
return new TaskBuilderImpl(this,
|
|
174
|
+
const startOptions = this.params.options ?? {};
|
|
175
|
+
const startOptionsOverrider = objectOverrider(startOptions);
|
|
176
|
+
return new TaskBuilderImpl(this, startOptionsOverrider());
|
|
177
177
|
}
|
|
178
178
|
async start(run, ...args) {
|
|
179
|
-
return this.
|
|
179
|
+
return this.startWithOptions(run, this.params.options ?? {}, ...args);
|
|
180
180
|
}
|
|
181
|
-
async
|
|
181
|
+
async startWithOptions(run, startOptions, ...args) {
|
|
182
182
|
const handle = run[INTERNAL].handle;
|
|
183
183
|
handle[INTERNAL].assertExecutionAllowed();
|
|
184
184
|
const inputRaw = args[0];
|
|
@@ -189,20 +189,19 @@ var TaskImpl = class {
|
|
|
189
189
|
if (replayManifest.hasUnconsumedEntries()) {
|
|
190
190
|
const existingTaskInfo = replayManifest.consumeNextTask(address);
|
|
191
191
|
if (existingTaskInfo) {
|
|
192
|
-
return this.getExistingTaskResult(run, handle,
|
|
192
|
+
return this.getExistingTaskResult(run, handle, startOptions, input, existingTaskInfo);
|
|
193
193
|
}
|
|
194
|
-
await this.throwNonDeterminismError(run, handle, inputHash, replayManifest);
|
|
194
|
+
await this.throwNonDeterminismError(run, handle, inputHash, replayManifest.getUnconsumedEntries());
|
|
195
195
|
}
|
|
196
196
|
const attempts = 1;
|
|
197
|
-
const retryStrategy =
|
|
197
|
+
const retryStrategy = startOptions.retry ?? { type: "never" };
|
|
198
198
|
const taskInfo = await handle[INTERNAL].transitionTaskState({
|
|
199
199
|
type: "create",
|
|
200
200
|
taskName: this.name,
|
|
201
|
-
options:
|
|
201
|
+
options: startOptions,
|
|
202
202
|
taskState: { status: "running", attempts, input }
|
|
203
203
|
});
|
|
204
204
|
const logger = run.logger.child({
|
|
205
|
-
"aiki.component": "task-execution",
|
|
206
205
|
"aiki.taskName": this.name,
|
|
207
206
|
"aiki.taskId": taskInfo.id
|
|
208
207
|
});
|
|
@@ -223,7 +222,7 @@ var TaskImpl = class {
|
|
|
223
222
|
logger.info("Task complete", { "aiki.attempts": lastAttempt });
|
|
224
223
|
return output;
|
|
225
224
|
}
|
|
226
|
-
async getExistingTaskResult(run, handle,
|
|
225
|
+
async getExistingTaskResult(run, handle, startOptions, input, existingTaskInfo) {
|
|
227
226
|
const existingTaskState = existingTaskInfo.state;
|
|
228
227
|
if (existingTaskState.status === "completed") {
|
|
229
228
|
return this.parse(handle, this.params.schema?.output, existingTaskState.output, run.logger);
|
|
@@ -237,7 +236,7 @@ var TaskImpl = class {
|
|
|
237
236
|
}
|
|
238
237
|
existingTaskState.status;
|
|
239
238
|
const attempts = existingTaskState.attempts;
|
|
240
|
-
const retryStrategy =
|
|
239
|
+
const retryStrategy = startOptions.retry ?? { type: "never" };
|
|
241
240
|
this.assertRetryAllowed(existingTaskInfo.id, attempts, retryStrategy, run.logger);
|
|
242
241
|
run.logger.debug("Retrying task", {
|
|
243
242
|
"aiki.taskName": this.name,
|
|
@@ -245,10 +244,9 @@ var TaskImpl = class {
|
|
|
245
244
|
"aiki.attempts": attempts,
|
|
246
245
|
"aiki.taskStatus": existingTaskState.status
|
|
247
246
|
});
|
|
248
|
-
return this.retryAndExecute(run, handle, input, existingTaskInfo.id,
|
|
247
|
+
return this.retryAndExecute(run, handle, input, existingTaskInfo.id, startOptions, retryStrategy, attempts);
|
|
249
248
|
}
|
|
250
|
-
async throwNonDeterminismError(run, handle, inputHash,
|
|
251
|
-
const unconsumedManifestEntries = manifest.getUnconsumedEntries();
|
|
249
|
+
async throwNonDeterminismError(run, handle, inputHash, unconsumedManifestEntries) {
|
|
252
250
|
run.logger.error("Replay divergence", {
|
|
253
251
|
"aiki.taskName": this.name,
|
|
254
252
|
"aiki.inputHash": inputHash,
|
|
@@ -262,16 +260,15 @@ var TaskImpl = class {
|
|
|
262
260
|
});
|
|
263
261
|
throw error;
|
|
264
262
|
}
|
|
265
|
-
async retryAndExecute(run, handle, input, taskId,
|
|
263
|
+
async retryAndExecute(run, handle, input, taskId, startOptions, retryStrategy, previousAttempts) {
|
|
266
264
|
const attempts = previousAttempts + 1;
|
|
267
265
|
const taskInfo = await handle[INTERNAL].transitionTaskState({
|
|
268
266
|
type: "retry",
|
|
269
267
|
taskId,
|
|
270
|
-
options:
|
|
268
|
+
options: startOptions,
|
|
271
269
|
taskState: { status: "running", attempts, input }
|
|
272
270
|
});
|
|
273
271
|
const logger = run.logger.child({
|
|
274
|
-
"aiki.component": "task-execution",
|
|
275
272
|
"aiki.taskName": this.name,
|
|
276
273
|
"aiki.taskId": taskInfo.id
|
|
277
274
|
});
|
|
@@ -372,15 +369,15 @@ var TaskImpl = class {
|
|
|
372
369
|
}
|
|
373
370
|
};
|
|
374
371
|
var TaskBuilderImpl = class _TaskBuilderImpl {
|
|
375
|
-
constructor(task2,
|
|
372
|
+
constructor(task2, startOptionsBuilder) {
|
|
376
373
|
this.task = task2;
|
|
377
|
-
this.
|
|
374
|
+
this.startOptionsBuilder = startOptionsBuilder;
|
|
378
375
|
}
|
|
379
376
|
opt(path, value) {
|
|
380
|
-
return new _TaskBuilderImpl(this.task, this.
|
|
377
|
+
return new _TaskBuilderImpl(this.task, this.startOptionsBuilder.with(path, value));
|
|
381
378
|
}
|
|
382
379
|
start(run, ...args) {
|
|
383
|
-
return this.task.
|
|
380
|
+
return this.task.startWithOptions(run, this.startOptionsBuilder.build(), ...args);
|
|
384
381
|
}
|
|
385
382
|
};
|
|
386
383
|
export {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aikirun/task",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.1",
|
|
4
4
|
"description": "Task SDK for Aiki - define reliable tasks with automatic retries, idempotency, and error handling",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -18,8 +18,7 @@
|
|
|
18
18
|
"build": "tsup"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@aikirun/types": "0.
|
|
22
|
-
"@aikirun/workflow": "0.23.1",
|
|
21
|
+
"@aikirun/types": "0.24.1",
|
|
23
22
|
"@standard-schema/spec": "^1.1.0"
|
|
24
23
|
},
|
|
25
24
|
"publishConfig": {
|