@ezghcloud/workflows 0.0.0-stage → 1.0.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/LICENSE +202 -0
- package/README.md +417 -2
- package/dist/client.d.ts +209 -0
- package/dist/client.js +259 -0
- package/dist/env.d.ts +2 -0
- package/dist/env.js +32 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +7 -0
- package/dist/protocol/bytes.d.ts +8 -0
- package/dist/protocol/bytes.js +49 -0
- package/dist/protocol/callback.d.ts +6 -0
- package/dist/protocol/callback.js +31 -0
- package/dist/protocol/codec.d.ts +6 -0
- package/dist/protocol/codec.js +38 -0
- package/dist/protocol/derived.d.ts +5 -0
- package/dist/protocol/derived.js +41 -0
- package/dist/protocol/index.d.ts +14 -0
- package/dist/protocol/index.js +21 -0
- package/dist/protocol/public.d.ts +2 -0
- package/dist/protocol/public.js +1 -0
- package/dist/protocol/signature.d.ts +17 -0
- package/dist/protocol/signature.js +101 -0
- package/dist/protocol/stepid.d.ts +4 -0
- package/dist/protocol/stepid.js +9 -0
- package/dist/protocol/tokens.d.ts +2 -0
- package/dist/protocol/tokens.js +38 -0
- package/dist/protocol/types.d.ts +185 -0
- package/dist/protocol/types.js +1 -0
- package/dist/protocol/validate.d.ts +15 -0
- package/dist/protocol/validate.js +279 -0
- package/dist/queues.d.ts +47 -0
- package/dist/queues.js +126 -0
- package/dist/runtime/context.d.ts +82 -0
- package/dist/runtime/context.js +1 -0
- package/dist/runtime/errors.d.ts +49 -0
- package/dist/runtime/errors.js +160 -0
- package/dist/runtime/execution.d.ts +17 -0
- package/dist/runtime/execution.js +608 -0
- package/dist/runtime/invocation.d.ts +5 -0
- package/dist/runtime/invocation.js +47 -0
- package/dist/runtime/live.d.ts +23 -0
- package/dist/runtime/live.js +103 -0
- package/dist/runtime/workflow.d.ts +26 -0
- package/dist/runtime/workflow.js +49 -0
- package/dist/serve.d.ts +12 -0
- package/dist/serve.js +149 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +2 -0
- package/dist/worker.d.ts +43 -0
- package/dist/worker.js +364 -0
- package/package.json +49 -4
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { truncateUtf8, utf8Length } from "../protocol/bytes.js";
|
|
2
|
+
// A step error that retrying won't fix: the step fails at once (code workflows.non_retriable).
|
|
3
|
+
export class NonRetriableError extends Error {
|
|
4
|
+
name = "NonRetriableError";
|
|
5
|
+
code = "workflows.non_retriable";
|
|
6
|
+
}
|
|
7
|
+
// A retryable step error with the delay before the next attempt.
|
|
8
|
+
export class RetryAfterError extends Error {
|
|
9
|
+
delayMs;
|
|
10
|
+
name = "RetryAfterError";
|
|
11
|
+
constructor(message, delayMs) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.delayMs = delayMs;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
// Thrown into a workflow's pending call when its run is cancelled (code workflows.cancelled).
|
|
17
|
+
export class CancelledError extends Error {
|
|
18
|
+
name = "CancelledError";
|
|
19
|
+
code = "workflows.cancelled";
|
|
20
|
+
}
|
|
21
|
+
// WorkflowError is an error with a code and JSON data, and what a recorded failure is rebuilt as
|
|
22
|
+
// on replay. Codes on the wire are "user" or the platform's own "workflows.*" codes: any other
|
|
23
|
+
// code is sent as "user", with
|
|
24
|
+
// the custom code as the name (when no name was given) and as data.code (when data is absent or a
|
|
25
|
+
// plain object without a code), so a replay sees code "user" and finds the custom code there.
|
|
26
|
+
export class WorkflowError extends Error {
|
|
27
|
+
code;
|
|
28
|
+
data;
|
|
29
|
+
constructor(message, opts = {}) {
|
|
30
|
+
super(message, opts.cause === undefined ? undefined : { cause: opts.cause });
|
|
31
|
+
this.code = opts.code ?? "user";
|
|
32
|
+
this.name = opts.name ?? "WorkflowError";
|
|
33
|
+
if (opts.data !== undefined)
|
|
34
|
+
this.data = opts.data;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// A callback that wasn't completed before its timeout: what Callback.wait() rejects with
|
|
38
|
+
// (code workflows.callback_timeout). Catchable; it isn't retried.
|
|
39
|
+
export class CallbackTimeout extends WorkflowError {
|
|
40
|
+
constructor(message, opts = {}) {
|
|
41
|
+
super(message, { ...opts, code: "workflows.callback_timeout", name: opts.name ?? "CallbackTimeout" });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// A child run that failed: what step.invoke rejects with (code workflows.child_failed); cause is
|
|
45
|
+
// the child's own error.
|
|
46
|
+
export class ChildFailed extends WorkflowError {
|
|
47
|
+
constructor(message, opts = {}) {
|
|
48
|
+
super(message, { ...opts, code: "workflows.child_failed", name: opts.name ?? "ChildFailed" });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// Errors the runtime raises itself.
|
|
52
|
+
export class StepTimeout extends Error {
|
|
53
|
+
name = "StepTimeout";
|
|
54
|
+
}
|
|
55
|
+
export class DuplicateStepName extends Error {
|
|
56
|
+
name = "DuplicateStepName";
|
|
57
|
+
}
|
|
58
|
+
export class OutputTooLarge extends Error {
|
|
59
|
+
name = "OutputTooLarge";
|
|
60
|
+
}
|
|
61
|
+
const MAX_STACK_BYTES = 8192;
|
|
62
|
+
const MAX_MESSAGE_BYTES = 8192;
|
|
63
|
+
const MAX_DATA_BYTES = 65_536;
|
|
64
|
+
// At most 8 levels in all, the error and 7 causes (internal/protocol MaxErrorDepth).
|
|
65
|
+
const MAX_DEPTH = 8;
|
|
66
|
+
// The platform's own codes (internal/protocol); a customer error with any other code is sent as user.
|
|
67
|
+
const PLATFORM_CODES = new Set([
|
|
68
|
+
"workflows.callback_timeout", "workflows.cancelled", "workflows.child_failed", "workflows.step_timeout",
|
|
69
|
+
"workflows.invocation_lost", "workflows.non_retriable", "workflows.output_too_large", "workflows.duplicate_step_name",
|
|
70
|
+
"workflows.workflow_not_found", "workflows.invocation_failed", "workflows.timed_out",
|
|
71
|
+
]);
|
|
72
|
+
const wireCode = (code) => code === "user" || PLATFORM_CODES.has(code);
|
|
73
|
+
const isPlainObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v) && Object.getPrototypeOf(v) === Object.prototype;
|
|
74
|
+
function codeOf(e) {
|
|
75
|
+
if (e instanceof NonRetriableError)
|
|
76
|
+
return "workflows.non_retriable";
|
|
77
|
+
if (e instanceof CancelledError)
|
|
78
|
+
return "workflows.cancelled";
|
|
79
|
+
if (e instanceof StepTimeout)
|
|
80
|
+
return "workflows.step_timeout";
|
|
81
|
+
if (e instanceof DuplicateStepName)
|
|
82
|
+
return "workflows.duplicate_step_name";
|
|
83
|
+
if (e instanceof OutputTooLarge)
|
|
84
|
+
return "workflows.output_too_large";
|
|
85
|
+
if (e instanceof WorkflowError)
|
|
86
|
+
return e.code;
|
|
87
|
+
return "user";
|
|
88
|
+
}
|
|
89
|
+
function jsonData(v) {
|
|
90
|
+
try {
|
|
91
|
+
return v === undefined ? undefined : JSON.parse(JSON.stringify(v));
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// encodeError: the wire shape of anything a workflow throws (design, "Errors"). Codes are "user"
|
|
98
|
+
// or "workflows.*" (see WorkflowError); messages and stacks are cut to 8 KiB of UTF-8 and data
|
|
99
|
+
// over 64 KiB of JSON is dropped; the error and its causes are at most 8 levels in all.
|
|
100
|
+
export function encodeError(e, depth = 0) {
|
|
101
|
+
if (!(e instanceof Error))
|
|
102
|
+
return { code: "user", name: "Error", message: truncateUtf8(typeof e === "string" ? e : safeString(e), MAX_MESSAGE_BYTES) };
|
|
103
|
+
let code = codeOf(e);
|
|
104
|
+
let name = e.name || "Error";
|
|
105
|
+
let data = jsonData(e.data);
|
|
106
|
+
if (!wireCode(code)) {
|
|
107
|
+
if (e instanceof WorkflowError && name === "WorkflowError")
|
|
108
|
+
name = code;
|
|
109
|
+
if (data === undefined)
|
|
110
|
+
data = { code };
|
|
111
|
+
else if (isPlainObject(data) && !("code" in data))
|
|
112
|
+
data = { ...data, code };
|
|
113
|
+
code = "user";
|
|
114
|
+
}
|
|
115
|
+
const w = { code, name: truncateUtf8(String(name), 256), message: truncateUtf8(String(e.message), MAX_MESSAGE_BYTES) };
|
|
116
|
+
if (data !== undefined && utf8Length(JSON.stringify(data)) <= MAX_DATA_BYTES)
|
|
117
|
+
w.data = data;
|
|
118
|
+
if (typeof e.stack === "string" && e.stack)
|
|
119
|
+
w.stack = truncateUtf8(e.stack, MAX_STACK_BYTES);
|
|
120
|
+
if (e.cause !== undefined && depth + 1 < MAX_DEPTH)
|
|
121
|
+
w.cause = encodeError(e.cause, depth + 1);
|
|
122
|
+
return w;
|
|
123
|
+
}
|
|
124
|
+
function safeString(v) {
|
|
125
|
+
try {
|
|
126
|
+
return String(v);
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return "A non-Error value was thrown";
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
// decodeError rebuilds the SDK's own classes from code, so instanceof works after replay.
|
|
133
|
+
// encodeError(decodeError(w)) gives back w.
|
|
134
|
+
export function decodeError(w) {
|
|
135
|
+
const cause = w.cause ? decodeError(w.cause) : undefined;
|
|
136
|
+
let e;
|
|
137
|
+
switch (w.code) {
|
|
138
|
+
case "workflows.non_retriable":
|
|
139
|
+
e = new NonRetriableError(w.message, cause ? { cause } : undefined);
|
|
140
|
+
break;
|
|
141
|
+
case "workflows.cancelled":
|
|
142
|
+
e = new CancelledError(w.message, cause ? { cause } : undefined);
|
|
143
|
+
break;
|
|
144
|
+
case "workflows.callback_timeout":
|
|
145
|
+
e = new CallbackTimeout(w.message, { name: w.name, data: w.data, cause });
|
|
146
|
+
break;
|
|
147
|
+
case "workflows.child_failed":
|
|
148
|
+
e = new ChildFailed(w.message, { name: w.name, data: w.data, cause });
|
|
149
|
+
break;
|
|
150
|
+
default: e = new WorkflowError(w.message, { code: w.code, name: w.name, data: w.data, cause });
|
|
151
|
+
}
|
|
152
|
+
e.name = w.name;
|
|
153
|
+
if (w.data !== undefined)
|
|
154
|
+
e.data = w.data;
|
|
155
|
+
if (w.stack !== undefined)
|
|
156
|
+
e.stack = w.stack;
|
|
157
|
+
else
|
|
158
|
+
delete e.stack;
|
|
159
|
+
return e;
|
|
160
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Command, Invocation } from "../protocol/index.ts";
|
|
2
|
+
import type { LiveIO } from "./live.ts";
|
|
3
|
+
import { type Workflow } from "./workflow.ts";
|
|
4
|
+
export interface ExecOptions {
|
|
5
|
+
now?: () => Date;
|
|
6
|
+
maxStepsPerInvocation?: number;
|
|
7
|
+
deadline?: number;
|
|
8
|
+
apiBaseUrl?: string;
|
|
9
|
+
cancelSignal?: AbortSignal;
|
|
10
|
+
maxResultBytes?: number;
|
|
11
|
+
}
|
|
12
|
+
export declare const MAX_SLEEP_MS = 31536000000;
|
|
13
|
+
export declare const MAX_RETRY_AFTER_MS = 86400000;
|
|
14
|
+
export declare const DEFAULT_CALLBACK_TIMEOUT_MS = 604800000;
|
|
15
|
+
export declare const MIN_CALLBACK_TIMEOUT_MS = 1000;
|
|
16
|
+
export declare const DEFAULT_API_BASE = "https://workflows-api.ezghcloud.com";
|
|
17
|
+
export declare function execute(inv: Invocation, wf: Workflow<any, any>, io: LiveIO, opts?: ExecOptions): Promise<Command[]>;
|