windmill-client 1.773.0 → 1.774.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/client.d.ts +75 -7
- package/dist/client.mjs +97 -58
- package/dist/core/OpenAPI.mjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +240 -58
- package/dist/services.gen.d.ts +21 -1
- package/dist/services.gen.mjs +42 -0
- package/dist/types.gen.d.ts +218 -3
- package/dist/wacError.d.ts +24 -0
- package/dist/wacError.mjs +103 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -126,7 +126,7 @@ const OpenAPI = {
|
|
|
126
126
|
PASSWORD: void 0,
|
|
127
127
|
TOKEN: getEnv$1("WM_TOKEN"),
|
|
128
128
|
USERNAME: void 0,
|
|
129
|
-
VERSION: "1.
|
|
129
|
+
VERSION: "1.774.0",
|
|
130
130
|
WITH_CREDENTIALS: true,
|
|
131
131
|
interceptors: {
|
|
132
132
|
request: new Interceptors(),
|
|
@@ -2761,6 +2761,24 @@ var WorkspaceService = class {
|
|
|
2761
2761
|
});
|
|
2762
2762
|
}
|
|
2763
2763
|
/**
|
|
2764
|
+
* check what the data table's database lets its role do
|
|
2765
|
+
* @param data The data for the request.
|
|
2766
|
+
* @param data.workspace
|
|
2767
|
+
* @param data.datatableName
|
|
2768
|
+
* @returns unknown connection and privilege report
|
|
2769
|
+
* @throws ApiError
|
|
2770
|
+
*/
|
|
2771
|
+
static testDataTableConnection(data) {
|
|
2772
|
+
return request(OpenAPI, {
|
|
2773
|
+
method: "GET",
|
|
2774
|
+
url: "/w/{workspace}/workspaces/test_datatable_connection/{datatable_name}",
|
|
2775
|
+
path: {
|
|
2776
|
+
workspace: data.workspace,
|
|
2777
|
+
datatable_name: data.datatableName
|
|
2778
|
+
}
|
|
2779
|
+
});
|
|
2780
|
+
}
|
|
2781
|
+
/**
|
|
2764
2782
|
* list tables of all connected Datatables
|
|
2765
2783
|
* @param data The data for the request.
|
|
2766
2784
|
* @param data.workspace
|
|
@@ -9582,6 +9600,30 @@ var JobService = class {
|
|
|
9582
9600
|
});
|
|
9583
9601
|
}
|
|
9584
9602
|
/**
|
|
9603
|
+
* get statuses and truncated results for all jobs of a flow job's execution tree
|
|
9604
|
+
* @param data The data for the request.
|
|
9605
|
+
* @param data.workspace
|
|
9606
|
+
* @param data.id
|
|
9607
|
+
* @param data.maxResultLen per-entry cap (in characters of JSON text) on result_prefix (default 2000, max 30000)
|
|
9608
|
+
* @param data.step step address to resolve to a single job instead of enumerating the tree: "b", "b/c", "b[12]" (1-based iteration/branch), composable as "b[12]/c"
|
|
9609
|
+
* @returns unknown per-job statuses and truncated results of the flow's execution tree, or the single resolved entry when step is provided
|
|
9610
|
+
* @throws ApiError
|
|
9611
|
+
*/
|
|
9612
|
+
static getFlowAllResults(data) {
|
|
9613
|
+
return request(OpenAPI, {
|
|
9614
|
+
method: "GET",
|
|
9615
|
+
url: "/w/{workspace}/jobs_u/get_flow_all_results/{id}",
|
|
9616
|
+
path: {
|
|
9617
|
+
workspace: data.workspace,
|
|
9618
|
+
id: data.id
|
|
9619
|
+
},
|
|
9620
|
+
query: {
|
|
9621
|
+
max_result_len: data.maxResultLen,
|
|
9622
|
+
step: data.step
|
|
9623
|
+
}
|
|
9624
|
+
});
|
|
9625
|
+
}
|
|
9626
|
+
/**
|
|
9585
9627
|
* get completed job logs tail
|
|
9586
9628
|
* @param data The data for the request.
|
|
9587
9629
|
* @param data.workspace
|
|
@@ -16453,6 +16495,108 @@ var HubPublishService = class {
|
|
|
16453
16495
|
}
|
|
16454
16496
|
};
|
|
16455
16497
|
|
|
16498
|
+
//#endregion
|
|
16499
|
+
//#region src/wacError.ts
|
|
16500
|
+
/** Error properties the executors already report as named fields, so they must
|
|
16501
|
+
* not be repeated inside `extra`. Kept identical to the skip-list in the
|
|
16502
|
+
* generated bun/deno job wrappers. */
|
|
16503
|
+
const SERIALIZED_ERROR_FIELDS = [
|
|
16504
|
+
"line",
|
|
16505
|
+
"name",
|
|
16506
|
+
"stack",
|
|
16507
|
+
"column",
|
|
16508
|
+
"message",
|
|
16509
|
+
"sourceURL",
|
|
16510
|
+
"originalLine",
|
|
16511
|
+
"originalColumn"
|
|
16512
|
+
];
|
|
16513
|
+
/** Read a property off a value that may fight back: a proxy `get` trap or a
|
|
16514
|
+
* throwing accessor turns an ordinary field read into an exception. Callers
|
|
16515
|
+
* are on the failure-reporting path, where nothing has been checkpointed yet. */
|
|
16516
|
+
function safeRead(o, k) {
|
|
16517
|
+
try {
|
|
16518
|
+
return o?.[k];
|
|
16519
|
+
} catch {
|
|
16520
|
+
return void 0;
|
|
16521
|
+
}
|
|
16522
|
+
}
|
|
16523
|
+
/** @internal
|
|
16524
|
+
* Whether a caught value is the SDK's own suspend signal, which must be
|
|
16525
|
+
* rethrown rather than reported as a step failure.
|
|
16526
|
+
*
|
|
16527
|
+
* Both halves of the check can throw on a hostile value: `instanceof` consults
|
|
16528
|
+
* a proxy's `getPrototypeOf` trap, and reading `.name` its `get` trap. This
|
|
16529
|
+
* runs before anything has been checkpointed, so neither may escape — a value
|
|
16530
|
+
* that fights back is simply not a suspend. */
|
|
16531
|
+
function isSuspendSignal(e, suspendCtor) {
|
|
16532
|
+
try {
|
|
16533
|
+
if (e instanceof suspendCtor) return true;
|
|
16534
|
+
} catch {}
|
|
16535
|
+
return safeRead(e, "name") === "StepSuspend";
|
|
16536
|
+
}
|
|
16537
|
+
/** @internal
|
|
16538
|
+
* Serialize a failed `step()` body into the `__wmill_error` marker that task
|
|
16539
|
+
* failures also use, so it can be stored in `completed_steps`.
|
|
16540
|
+
*
|
|
16541
|
+
* The record's final shape is decided by the backend (`wac_failure_record`),
|
|
16542
|
+
* which normalizes task failures through the same function; what is built here
|
|
16543
|
+
* is the raw material plus the envelope the backend recognizes. */
|
|
16544
|
+
function stepErrorMarker(key, e) {
|
|
16545
|
+
const thrown = e;
|
|
16546
|
+
const rawName = safeRead(thrown, "name");
|
|
16547
|
+
const rawMessage = safeRead(thrown, "message");
|
|
16548
|
+
const rawStack = safeRead(thrown, "stack");
|
|
16549
|
+
const name = typeof rawName === "string" ? rawName : void 0;
|
|
16550
|
+
const message = typeof rawMessage === "string" ? rawMessage : void 0;
|
|
16551
|
+
const stack = typeof rawStack === "string" ? rawStack : void 0;
|
|
16552
|
+
const error = {};
|
|
16553
|
+
if (name) error.name = name;
|
|
16554
|
+
if (message !== void 0) error.message = message;
|
|
16555
|
+
if (stack) error.stack = stack;
|
|
16556
|
+
if (thrown !== null && typeof thrown === "object") {
|
|
16557
|
+
const extra = {};
|
|
16558
|
+
let keys = [];
|
|
16559
|
+
try {
|
|
16560
|
+
keys = Object.getOwnPropertyNames(thrown);
|
|
16561
|
+
} catch {
|
|
16562
|
+
keys = [];
|
|
16563
|
+
}
|
|
16564
|
+
for (const k of keys) {
|
|
16565
|
+
if (SERIALIZED_ERROR_FIELDS.includes(k)) continue;
|
|
16566
|
+
try {
|
|
16567
|
+
extra[k] = JSON.parse(JSON.stringify(thrown[k]));
|
|
16568
|
+
} catch {}
|
|
16569
|
+
}
|
|
16570
|
+
if (Object.keys(extra).length > 0) error.extra = extra;
|
|
16571
|
+
}
|
|
16572
|
+
let fallback;
|
|
16573
|
+
try {
|
|
16574
|
+
fallback = String(e);
|
|
16575
|
+
} catch {
|
|
16576
|
+
fallback = `unrepresentable ${typeof e} thrown`;
|
|
16577
|
+
}
|
|
16578
|
+
return {
|
|
16579
|
+
__wmill_error: true,
|
|
16580
|
+
message: message ?? fallback,
|
|
16581
|
+
step_key: key,
|
|
16582
|
+
result: { error }
|
|
16583
|
+
};
|
|
16584
|
+
}
|
|
16585
|
+
/** @internal
|
|
16586
|
+
* Rebuild the error a failed task or step throws. The run that produced the
|
|
16587
|
+
* failure and every later replay go through here: a catch is control flow,
|
|
16588
|
+
* `workflow()` re-runs its body from the top every round, so a handler that
|
|
16589
|
+
* branches on the failure it caught must be handed the same thing in every
|
|
16590
|
+
* round or it dispatches different tasks on the way back. */
|
|
16591
|
+
function taskErrorFromMarker(marker, fallbackMessage) {
|
|
16592
|
+
const err = new Error(marker?.message || fallbackMessage);
|
|
16593
|
+
err.name = "TaskError";
|
|
16594
|
+
err.result = marker?.result;
|
|
16595
|
+
err.step_key = marker?.step_key;
|
|
16596
|
+
err.child_job_id = marker?.child_job_id;
|
|
16597
|
+
return err;
|
|
16598
|
+
}
|
|
16599
|
+
|
|
16456
16600
|
//#endregion
|
|
16457
16601
|
//#region src/s3Types.ts
|
|
16458
16602
|
/**
|
|
@@ -17786,31 +17930,24 @@ var StepSuspend = class extends Error {
|
|
|
17786
17930
|
this.name = "StepSuspend";
|
|
17787
17931
|
}
|
|
17788
17932
|
};
|
|
17789
|
-
/**
|
|
17790
|
-
*
|
|
17791
|
-
|
|
17792
|
-
|
|
17793
|
-
|
|
17794
|
-
return
|
|
17795
|
-
__wmill_error: true,
|
|
17796
|
-
message,
|
|
17797
|
-
step_key: key,
|
|
17798
|
-
result: {
|
|
17799
|
-
error: message,
|
|
17800
|
-
type
|
|
17801
|
-
}
|
|
17802
|
-
};
|
|
17933
|
+
/** Encode a checkpoint payload the way the worker wrapper does on the suspend
|
|
17934
|
+
* path, so both arms record the same value for the same step. `undefined` maps
|
|
17935
|
+
* to null; a bigint to its digits, which the wrapper gets instead from the
|
|
17936
|
+
* `BigInt.prototype.toJSON` it installs and the SDK cannot count on. */
|
|
17937
|
+
function encodeCheckpointPayload(payload) {
|
|
17938
|
+
return JSON.stringify(payload, (_key, value) => typeof value === "undefined" ? null : typeof value === "bigint" ? value.toString() : value);
|
|
17803
17939
|
}
|
|
17804
|
-
/**
|
|
17805
|
-
*
|
|
17806
|
-
*
|
|
17807
|
-
function
|
|
17808
|
-
|
|
17809
|
-
|
|
17810
|
-
|
|
17811
|
-
|
|
17812
|
-
|
|
17813
|
-
|
|
17940
|
+
/** A whole result that `JSON.stringify` drops the key for leaves a checkpoint
|
|
17941
|
+
* with no `result`, which neither the endpoint nor `WacOutput` accepts. Only
|
|
17942
|
+
* the top level: nested, a dropped key is what every other bun path does. */
|
|
17943
|
+
function checkpointableResult(value) {
|
|
17944
|
+
return typeof value === "function" || typeof value === "symbol" ? null : value;
|
|
17945
|
+
}
|
|
17946
|
+
/** Put a value through the checkpoint's encoding without checkpointing it, so
|
|
17947
|
+
* the paths that never persist anything still hand back the shape the ones
|
|
17948
|
+
* that do would. */
|
|
17949
|
+
function jsonRoundTrip(value) {
|
|
17950
|
+
return JSON.parse(encodeCheckpointPayload({ value: checkpointableResult(value) })).value;
|
|
17814
17951
|
}
|
|
17815
17952
|
/** A step key travels as one path segment when its URLs are minted, so it must be
|
|
17816
17953
|
* non-empty and free of `/` and dot segments — otherwise `waitForApproval` would
|
|
@@ -17838,6 +17975,11 @@ var WorkflowCtx = class {
|
|
|
17838
17975
|
* `complete` whose step never reached `completed_steps`. Python is immune:
|
|
17839
17976
|
* `_StepSuspend` derives from `BaseException`. */
|
|
17840
17977
|
_pendingSuspend = null;
|
|
17978
|
+
/** The failure raised by the step this child round is executing. That exception
|
|
17979
|
+
* *is* the round's result, so a `catch` in the body must not be able to turn it
|
|
17980
|
+
* into a `complete` — the parent would then record the caught branch's value as
|
|
17981
|
+
* a successful step. Boxed: the thrown value may be any falsy value. */
|
|
17982
|
+
_pendingStepFailure = null;
|
|
17841
17983
|
/** When set, the task matching this key executes its inner function directly */
|
|
17842
17984
|
_executingKey;
|
|
17843
17985
|
/** Serializes fast-path POSTs across concurrent step() calls within one
|
|
@@ -17870,16 +18012,12 @@ var WorkflowCtx = class {
|
|
|
17870
18012
|
return key;
|
|
17871
18013
|
}
|
|
17872
18014
|
_nextStep(name, script, args = {}, dispatch_type = "inline", options) {
|
|
17873
|
-
this.
|
|
18015
|
+
this._rethrowSwallowed();
|
|
17874
18016
|
const key = this._allocKey(name || script || "step");
|
|
17875
18017
|
if (key in this.completed) {
|
|
17876
18018
|
const value = this.completed[key];
|
|
17877
18019
|
if (value && typeof value === "object" && value.__wmill_error) {
|
|
17878
|
-
const err =
|
|
17879
|
-
err.name = "TaskError";
|
|
17880
|
-
err.result = value.result;
|
|
17881
|
-
err.step_key = value.step_key;
|
|
17882
|
-
err.child_job_id = value.child_job_id;
|
|
18020
|
+
const err = taskErrorFromMarker(value, `Task '${name}' failed`);
|
|
17883
18021
|
return { then: (_resolve, reject) => {
|
|
17884
18022
|
if (reject) reject(err);
|
|
17885
18023
|
else throw err;
|
|
@@ -17929,7 +18067,7 @@ var WorkflowCtx = class {
|
|
|
17929
18067
|
return steps;
|
|
17930
18068
|
}
|
|
17931
18069
|
_waitForApproval(options) {
|
|
17932
|
-
this.
|
|
18070
|
+
this._rethrowSwallowed();
|
|
17933
18071
|
if (options?.key !== void 0) assertUsableStepKey(options.key, "waitForApproval key");
|
|
17934
18072
|
const key = this._allocKey(options?.key || "approval");
|
|
17935
18073
|
if (options?.key && key !== options.key) throw new Error(`WAC step key "${options.key}" is already used in this workflow. Give each waitForApproval() its own key so getApprovalUrls() can address it.`);
|
|
@@ -17949,7 +18087,7 @@ var WorkflowCtx = class {
|
|
|
17949
18087
|
});
|
|
17950
18088
|
}
|
|
17951
18089
|
_sleep(seconds) {
|
|
17952
|
-
this.
|
|
18090
|
+
this._rethrowSwallowed();
|
|
17953
18091
|
const key = this._allocKey("sleep");
|
|
17954
18092
|
if (key in this.completed) return { then: (resolve$1) => resolve$1(void 0) };
|
|
17955
18093
|
if (this._executingKey !== null) return { then: () => new Promise(() => {}) };
|
|
@@ -17962,11 +18100,11 @@ var WorkflowCtx = class {
|
|
|
17962
18100
|
});
|
|
17963
18101
|
}
|
|
17964
18102
|
async _runInlineStep(name, fn) {
|
|
17965
|
-
this.
|
|
18103
|
+
this._rethrowSwallowed();
|
|
17966
18104
|
const key = this._allocKey(name || "step");
|
|
17967
18105
|
if (key in this.completed) {
|
|
17968
18106
|
const value = this.completed[key];
|
|
17969
|
-
if (value && typeof value === "object" && value.__wmill_error) throw
|
|
18107
|
+
if (value && typeof value === "object" && value.__wmill_error) throw taskErrorFromMarker(value, `Step '${name}' failed`);
|
|
17970
18108
|
return value;
|
|
17971
18109
|
}
|
|
17972
18110
|
if (this._executingKey !== null) return new Promise(() => {});
|
|
@@ -17978,22 +18116,36 @@ var WorkflowCtx = class {
|
|
|
17978
18116
|
})}`);
|
|
17979
18117
|
const t0 = Date.now();
|
|
17980
18118
|
let result;
|
|
17981
|
-
let stepError;
|
|
17982
18119
|
let errored = false;
|
|
17983
18120
|
try {
|
|
17984
18121
|
result = await fn();
|
|
17985
18122
|
} catch (e) {
|
|
17986
|
-
if (e
|
|
18123
|
+
if (isSuspendSignal(e, StepSuspend)) throw e;
|
|
17987
18124
|
errored = true;
|
|
17988
|
-
stepError = e;
|
|
17989
18125
|
result = stepErrorMarker(key, e);
|
|
18126
|
+
console.log(`--- WAC: ${key} failed ---`);
|
|
18127
|
+
console.log(result?.result?.error?.stack ?? result?.message ?? "step failed");
|
|
17990
18128
|
}
|
|
17991
18129
|
const durationMs = Date.now() - t0;
|
|
17992
18130
|
const fastPathFlagRaw = (getEnv("WM_WAC_INLINE_FAST_PATH") ?? "1").trim().toLowerCase();
|
|
17993
18131
|
const fastPathEnabled = fastPathFlagRaw !== "0" && fastPathFlagRaw !== "false" && fastPathFlagRaw !== "off" && fastPathFlagRaw !== "no";
|
|
17994
18132
|
const jobId = getEnv("WM_JOB_ID");
|
|
17995
18133
|
const workspace = getEnv("WM_WORKSPACE");
|
|
17996
|
-
|
|
18134
|
+
let payload;
|
|
18135
|
+
let checkpointed;
|
|
18136
|
+
if (fastPathEnabled && jobId && workspace && OpenAPI.BASE && OpenAPI.TOKEN) try {
|
|
18137
|
+
payload = encodeCheckpointPayload({
|
|
18138
|
+
key,
|
|
18139
|
+
result: checkpointableResult(result),
|
|
18140
|
+
started_at: startedAt,
|
|
18141
|
+
duration_ms: durationMs
|
|
18142
|
+
});
|
|
18143
|
+
checkpointed = JSON.parse(payload).result;
|
|
18144
|
+
} catch (e) {
|
|
18145
|
+
console.log(`WAC v2 inline fast path could not serialize key ${key}, falling back to suspend: ${e}`);
|
|
18146
|
+
}
|
|
18147
|
+
if (payload !== void 0) {
|
|
18148
|
+
const body = payload;
|
|
17997
18149
|
const chainTail = this._inlineChain.then(async () => {
|
|
17998
18150
|
const ctrl = new AbortController();
|
|
17999
18151
|
const t = setTimeout(() => ctrl.abort(), 1e4);
|
|
@@ -18004,37 +18156,36 @@ var WorkflowCtx = class {
|
|
|
18004
18156
|
"Content-Type": "application/json",
|
|
18005
18157
|
Authorization: `Bearer ${OpenAPI.TOKEN}`
|
|
18006
18158
|
},
|
|
18007
|
-
body
|
|
18008
|
-
key,
|
|
18009
|
-
result,
|
|
18010
|
-
started_at: startedAt,
|
|
18011
|
-
duration_ms: durationMs
|
|
18012
|
-
}),
|
|
18159
|
+
body,
|
|
18013
18160
|
signal: ctrl.signal
|
|
18014
18161
|
});
|
|
18015
18162
|
if (!resp.ok) throw new Error(`inline_checkpoint API ${resp.status}`);
|
|
18163
|
+
if (!errored) return void 0;
|
|
18164
|
+
if (!(resp.headers.get("content-type") ?? "").includes("json")) return void 0;
|
|
18165
|
+
return (await resp.json())?.failure;
|
|
18016
18166
|
} finally {
|
|
18017
18167
|
clearTimeout(t);
|
|
18018
18168
|
}
|
|
18019
18169
|
});
|
|
18020
18170
|
this._inlineChain = chainTail.catch(() => {});
|
|
18021
18171
|
let fastPathOk = false;
|
|
18172
|
+
let storedFailure;
|
|
18022
18173
|
try {
|
|
18023
|
-
await chainTail;
|
|
18174
|
+
storedFailure = await chainTail;
|
|
18024
18175
|
fastPathOk = true;
|
|
18025
18176
|
} catch (e) {
|
|
18026
18177
|
console.log(`WAC v2 inline fast path failed for key ${key}, falling back to suspend: ${e}`);
|
|
18027
18178
|
}
|
|
18028
18179
|
if (fastPathOk) {
|
|
18029
|
-
if (errored) throw
|
|
18030
|
-
return
|
|
18180
|
+
if (errored) throw taskErrorFromMarker(storedFailure ?? checkpointed, `Step '${name}' failed`);
|
|
18181
|
+
return checkpointed;
|
|
18031
18182
|
}
|
|
18032
18183
|
}
|
|
18033
18184
|
this._raiseSuspend({
|
|
18034
18185
|
mode: "inline_checkpoint",
|
|
18035
18186
|
steps: [],
|
|
18036
18187
|
key,
|
|
18037
|
-
result,
|
|
18188
|
+
result: checkpointableResult(result),
|
|
18038
18189
|
started_at: startedAt,
|
|
18039
18190
|
duration_ms: durationMs
|
|
18040
18191
|
});
|
|
@@ -18046,11 +18197,18 @@ var WorkflowCtx = class {
|
|
|
18046
18197
|
this._pendingSuspend = suspend;
|
|
18047
18198
|
throw suspend;
|
|
18048
18199
|
}
|
|
18049
|
-
/**
|
|
18050
|
-
*
|
|
18051
|
-
|
|
18052
|
-
|
|
18053
|
-
|
|
18200
|
+
/** Park then raise the executing step's failure. Child mode only — in a parent
|
|
18201
|
+
* round a task failure is an ordinary `TaskError` the body may handle. */
|
|
18202
|
+
_raiseStepFailure(error) {
|
|
18203
|
+
this._pendingStepFailure = { error };
|
|
18204
|
+
throw error;
|
|
18205
|
+
}
|
|
18206
|
+
/** Re-throw a swallowed suspend or step failure at the next SDK call. It
|
|
18207
|
+
* happened before whatever the body is doing now, so it wins: the run is
|
|
18208
|
+
* unwinding either way and everything after it re-runs on the replay. Left
|
|
18209
|
+
* set, so a body that catches in a loop can't swallow it a second time. */
|
|
18210
|
+
_rethrowSwallowed() {
|
|
18211
|
+
if (this._pendingStepFailure) throw this._pendingStepFailure.error;
|
|
18054
18212
|
if (this._pendingSuspend) throw this._pendingSuspend;
|
|
18055
18213
|
}
|
|
18056
18214
|
/** Hand the runner a suspend the workflow body caught and swallowed, so it is
|
|
@@ -18061,16 +18219,30 @@ var WorkflowCtx = class {
|
|
|
18061
18219
|
this._pendingSuspend = null;
|
|
18062
18220
|
return s;
|
|
18063
18221
|
}
|
|
18222
|
+
/** Same for the executing step's failure, so the runner can fail the child job. */
|
|
18223
|
+
_takePendingStepFailure() {
|
|
18224
|
+
const f = this._pendingStepFailure;
|
|
18225
|
+
this._pendingStepFailure = null;
|
|
18226
|
+
return f;
|
|
18227
|
+
}
|
|
18064
18228
|
};
|
|
18065
18229
|
async function sleep(seconds) {
|
|
18066
18230
|
const ctx = _workflowCtx ?? Reflect.get(globalThis, "__wmill_wf_ctx");
|
|
18067
18231
|
if (ctx) return ctx._sleep(seconds);
|
|
18068
18232
|
await new Promise((r) => setTimeout(r, seconds * 1e3));
|
|
18069
18233
|
}
|
|
18234
|
+
/**
|
|
18235
|
+
* Execute `fn` inline and checkpoint the result. On replay the cached value is
|
|
18236
|
+
* returned without re-executing `fn`.
|
|
18237
|
+
*
|
|
18238
|
+
* `fn`'s result is encoded as JSON and decoded back before it is returned, so
|
|
18239
|
+
* the round that runs the body sees the same types every replay sees: a `Date`
|
|
18240
|
+
* comes back as a string, a `Map` as `{}`. {@link Jsonified} is that shape.
|
|
18241
|
+
*/
|
|
18070
18242
|
async function step(name, fn) {
|
|
18071
18243
|
const ctx = _workflowCtx ?? Reflect.get(globalThis, "__wmill_wf_ctx");
|
|
18072
18244
|
if (ctx) return ctx._runInlineStep(name, fn);
|
|
18073
|
-
return fn();
|
|
18245
|
+
return jsonRoundTrip(await fn());
|
|
18074
18246
|
}
|
|
18075
18247
|
/**
|
|
18076
18248
|
* Wrap an async function as a workflow task.
|
|
@@ -18081,6 +18253,10 @@ async function step(name, fn) {
|
|
|
18081
18253
|
*
|
|
18082
18254
|
* Inside a `workflow()`, calling a task dispatches it as a step.
|
|
18083
18255
|
* Outside a workflow, the function body executes directly.
|
|
18256
|
+
*
|
|
18257
|
+
* A task runs as its own job, so its result is always encoded as JSON and
|
|
18258
|
+
* decoded back before the caller sees it: a `Date` comes back as a string, a
|
|
18259
|
+
* `Map` as `{}`. {@link JsonifiedFn} is that shape.
|
|
18084
18260
|
*/
|
|
18085
18261
|
function task(fnOrPath, maybeFnOrOptions, maybeOptions) {
|
|
18086
18262
|
let fn;
|
|
@@ -18105,11 +18281,17 @@ function task(fnOrPath, maybeFnOrOptions, maybeOptions) {
|
|
|
18105
18281
|
else kwargs[`arg${i}`] = args[i];
|
|
18106
18282
|
const stepResult = ctx._nextStep(taskName, script, kwargs, "inline", taskOptions);
|
|
18107
18283
|
if (stepResult?._execute_directly) return (async () => {
|
|
18108
|
-
|
|
18284
|
+
let result;
|
|
18285
|
+
try {
|
|
18286
|
+
result = await fn(...args);
|
|
18287
|
+
} catch (e) {
|
|
18288
|
+
if (isSuspendSignal(e, StepSuspend)) throw e;
|
|
18289
|
+
ctx._raiseStepFailure(e);
|
|
18290
|
+
}
|
|
18109
18291
|
ctx._raiseSuspend({
|
|
18110
18292
|
mode: "step_complete",
|
|
18111
18293
|
steps: [],
|
|
18112
|
-
result
|
|
18294
|
+
result: checkpointableResult(result)
|
|
18113
18295
|
});
|
|
18114
18296
|
})();
|
|
18115
18297
|
return stepResult;
|
|
@@ -18131,7 +18313,7 @@ function task(fnOrPath, maybeFnOrOptions, maybeOptions) {
|
|
|
18131
18313
|
console.log(`Task ${taskName} (${jobId}) completed`);
|
|
18132
18314
|
return r;
|
|
18133
18315
|
})();
|
|
18134
|
-
else return fn(...args);
|
|
18316
|
+
else return Promise.resolve(fn(...args)).then(jsonRoundTrip);
|
|
18135
18317
|
};
|
|
18136
18318
|
Object.defineProperty(wrapper, "name", { value: taskName });
|
|
18137
18319
|
wrapper._is_task = true;
|