pg-workflows 0.15.0 → 0.16.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.entry.cjs +68 -23
- package/dist/client.entry.d.cts +6 -1
- package/dist/client.entry.d.ts +6 -1
- package/dist/client.entry.js +1 -1
- package/dist/client.entry.js.map +7 -7
- package/dist/index.cjs +77 -193
- package/dist/index.d.cts +18 -11
- package/dist/index.d.ts +18 -11
- package/dist/index.js +13 -176
- package/dist/index.js.map +9 -10
- package/dist/shared/{chunk-n0f7hd40.js → chunk-d204nxd5.js} +48 -3
- package/dist/shared/chunk-d204nxd5.js.map +17 -0
- package/package.json +13 -30
- package/LICENSE +0 -22
- package/README.md +0 -216
- package/dist/shared/chunk-n0f7hd40.js.map +0 -17
package/dist/index.cjs
CHANGED
|
@@ -65,7 +65,7 @@ var __export = (target, all) => {
|
|
|
65
65
|
var exports_src = {};
|
|
66
66
|
__export(exports_src, {
|
|
67
67
|
workflow: () => workflow,
|
|
68
|
-
|
|
68
|
+
isStepCached: () => isStepCached,
|
|
69
69
|
createWorkflowRef: () => createWorkflowRef,
|
|
70
70
|
WorkflowStatus: () => WorkflowStatus,
|
|
71
71
|
WorkflowRunNotFoundError: () => WorkflowRunNotFoundError,
|
|
@@ -95,6 +95,7 @@ var WAIT_FOR_TIMELINE_SUFFIX = "wait-for";
|
|
|
95
95
|
var invokeChildWorkflowTimelineKey = (stepId) => `${stepId}-${INVOKE_CHILD_WORKFLOW_TIMELINE_SUFFIX}`;
|
|
96
96
|
var waitForTimelineKey = (stepId) => `${stepId}-${WAIT_FOR_TIMELINE_SUFFIX}`;
|
|
97
97
|
var isInvokeChildWorkflowTimelineEntry = (entry) => !!entry && typeof entry === "object" && ("invokeChildWorkflow" in entry);
|
|
98
|
+
var isStepCached = (timeline, stepId) => timeline[stepId]?.output !== undefined || isInvokeChildWorkflowTimelineEntry(timeline[invokeChildWorkflowTimelineKey(stepId)]);
|
|
98
99
|
|
|
99
100
|
// src/db/migration.ts
|
|
100
101
|
var MIGRATION_LOCK_ID = 738291645;
|
|
@@ -269,7 +270,37 @@ class WorkflowRunInProgressError extends WorkflowEngineError {
|
|
|
269
270
|
}
|
|
270
271
|
}
|
|
271
272
|
|
|
273
|
+
// src/types.ts
|
|
274
|
+
var WorkflowStatus;
|
|
275
|
+
((WorkflowStatus2) => {
|
|
276
|
+
WorkflowStatus2["PENDING"] = "pending";
|
|
277
|
+
WorkflowStatus2["RUNNING"] = "running";
|
|
278
|
+
WorkflowStatus2["PAUSED"] = "paused";
|
|
279
|
+
WorkflowStatus2["COMPLETED"] = "completed";
|
|
280
|
+
WorkflowStatus2["FAILED"] = "failed";
|
|
281
|
+
WorkflowStatus2["CANCELLED"] = "cancelled";
|
|
282
|
+
})(WorkflowStatus ||= {});
|
|
283
|
+
var _STEP_BASE_METHOD_TO_TYPE = {
|
|
284
|
+
run: "run" /* RUN */,
|
|
285
|
+
waitFor: "waitFor" /* WAIT_FOR */,
|
|
286
|
+
waitUntil: "waitUntil" /* WAIT_UNTIL */,
|
|
287
|
+
delay: "delay" /* DELAY */,
|
|
288
|
+
sleep: "delay" /* DELAY */,
|
|
289
|
+
pause: "pause" /* PAUSE */,
|
|
290
|
+
poll: "poll" /* POLL */,
|
|
291
|
+
invokeChildWorkflow: "invokeChildWorkflow" /* INVOKE_CHILD_WORKFLOW */
|
|
292
|
+
};
|
|
293
|
+
var STEP_BASE_METHOD_TYPES = new Map(Object.entries(_STEP_BASE_METHOD_TO_TYPE));
|
|
294
|
+
|
|
272
295
|
// src/db/queries.ts
|
|
296
|
+
var EMPTY_RUN_STATS = {
|
|
297
|
+
["pending" /* PENDING */]: 0,
|
|
298
|
+
["running" /* RUNNING */]: 0,
|
|
299
|
+
["paused" /* PAUSED */]: 0,
|
|
300
|
+
["completed" /* COMPLETED */]: 0,
|
|
301
|
+
["failed" /* FAILED */]: 0,
|
|
302
|
+
["cancelled" /* CANCELLED */]: 0
|
|
303
|
+
};
|
|
273
304
|
function generateKSUID(prefix) {
|
|
274
305
|
return `${prefix ? `${prefix}_` : ""}${import_ksuid.default.randomSync().string}`;
|
|
275
306
|
}
|
|
@@ -617,6 +648,32 @@ async function getWorkflowRuns({
|
|
|
617
648
|
const prevCursor = hasPrev && items.length > 0 ? items[0]?.id ?? null : null;
|
|
618
649
|
return { items, nextCursor, prevCursor, hasMore, hasPrev };
|
|
619
650
|
}
|
|
651
|
+
async function getWorkflowRunStats({
|
|
652
|
+
resourceId,
|
|
653
|
+
workflowId
|
|
654
|
+
}, db) {
|
|
655
|
+
const conditions = [];
|
|
656
|
+
const values = [];
|
|
657
|
+
let paramIndex = 1;
|
|
658
|
+
if (resourceId) {
|
|
659
|
+
conditions.push(`resource_id = $${paramIndex}`);
|
|
660
|
+
values.push(resourceId);
|
|
661
|
+
paramIndex++;
|
|
662
|
+
}
|
|
663
|
+
if (workflowId) {
|
|
664
|
+
conditions.push(`workflow_id = $${paramIndex}`);
|
|
665
|
+
values.push(workflowId);
|
|
666
|
+
}
|
|
667
|
+
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
668
|
+
const result = await db.executeSql(`SELECT status, COUNT(*)::int AS count FROM workflow_runs ${whereClause} GROUP BY status`, values);
|
|
669
|
+
const stats = { ...EMPTY_RUN_STATS };
|
|
670
|
+
for (const row of result.rows) {
|
|
671
|
+
if (row.status in stats) {
|
|
672
|
+
stats[row.status] = Number(row.count);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
return stats;
|
|
676
|
+
}
|
|
620
677
|
async function withPostgresTransaction(db, callback, pool) {
|
|
621
678
|
let txDb;
|
|
622
679
|
let release;
|
|
@@ -666,28 +723,6 @@ function resolvePriority(...candidates) {
|
|
|
666
723
|
return PRIORITY_LEVELS.normal;
|
|
667
724
|
}
|
|
668
725
|
|
|
669
|
-
// src/types.ts
|
|
670
|
-
var WorkflowStatus;
|
|
671
|
-
((WorkflowStatus2) => {
|
|
672
|
-
WorkflowStatus2["PENDING"] = "pending";
|
|
673
|
-
WorkflowStatus2["RUNNING"] = "running";
|
|
674
|
-
WorkflowStatus2["PAUSED"] = "paused";
|
|
675
|
-
WorkflowStatus2["COMPLETED"] = "completed";
|
|
676
|
-
WorkflowStatus2["FAILED"] = "failed";
|
|
677
|
-
WorkflowStatus2["CANCELLED"] = "cancelled";
|
|
678
|
-
})(WorkflowStatus ||= {});
|
|
679
|
-
var _STEP_BASE_METHOD_TO_TYPE = {
|
|
680
|
-
run: "run" /* RUN */,
|
|
681
|
-
waitFor: "waitFor" /* WAIT_FOR */,
|
|
682
|
-
waitUntil: "waitUntil" /* WAIT_UNTIL */,
|
|
683
|
-
delay: "delay" /* DELAY */,
|
|
684
|
-
sleep: "delay" /* DELAY */,
|
|
685
|
-
pause: "pause" /* PAUSE */,
|
|
686
|
-
poll: "poll" /* POLL */,
|
|
687
|
-
invokeChildWorkflow: "invokeChildWorkflow" /* INVOKE_CHILD_WORKFLOW */
|
|
688
|
-
};
|
|
689
|
-
var STEP_BASE_METHOD_TYPES = new Map(Object.entries(_STEP_BASE_METHOD_TO_TYPE));
|
|
690
|
-
|
|
691
726
|
// src/client.ts
|
|
692
727
|
var LOG_PREFIX = "[WorkflowClient]";
|
|
693
728
|
var defaultLogger = {
|
|
@@ -996,6 +1031,16 @@ class WorkflowClient {
|
|
|
996
1031
|
workflowId
|
|
997
1032
|
}, this.db);
|
|
998
1033
|
}
|
|
1034
|
+
async getStats({
|
|
1035
|
+
resourceId,
|
|
1036
|
+
workflowId
|
|
1037
|
+
} = {}) {
|
|
1038
|
+
await this.ensureStarted();
|
|
1039
|
+
if (workflowId)
|
|
1040
|
+
validateWorkflowId(workflowId);
|
|
1041
|
+
validateResourceId(resourceId);
|
|
1042
|
+
return getWorkflowRunStats({ resourceId, workflowId }, this.db);
|
|
1043
|
+
}
|
|
999
1044
|
async ensureStarted() {
|
|
1000
1045
|
if (!this._started) {
|
|
1001
1046
|
await this.start();
|
|
@@ -2425,177 +2470,16 @@ ${error.stack}` : String(error)
|
|
|
2425
2470
|
workflowId
|
|
2426
2471
|
}, this.db);
|
|
2427
2472
|
}
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
return
|
|
2436
|
-
}
|
|
2437
|
-
if (kind === "invokeChildWorkflow" && timeline[invokeChildWorkflowTimelineKey(stepId)]) {
|
|
2438
|
-
return true;
|
|
2473
|
+
async getStats({
|
|
2474
|
+
resourceId,
|
|
2475
|
+
workflowId
|
|
2476
|
+
} = {}) {
|
|
2477
|
+
if (workflowId)
|
|
2478
|
+
validateWorkflowId(workflowId);
|
|
2479
|
+
validateResourceId(resourceId);
|
|
2480
|
+
return getWorkflowRunStats({ resourceId, workflowId }, this.db);
|
|
2439
2481
|
}
|
|
2440
|
-
return false;
|
|
2441
|
-
}
|
|
2442
|
-
function otelPlugin(options = {}) {
|
|
2443
|
-
const tracer = options.tracer ?? import_api.trace.getTracer("pg-workflows");
|
|
2444
|
-
const prefix = options.spanNamePrefix ?? DEFAULT_PREFIX;
|
|
2445
|
-
const extraAttrs = options.attributes;
|
|
2446
|
-
return {
|
|
2447
|
-
name: "opentelemetry",
|
|
2448
|
-
methods: (step, context) => {
|
|
2449
|
-
const wrapVoidish = (kind, base) => {
|
|
2450
|
-
return async (stepId, ...args) => {
|
|
2451
|
-
if (isCachedHit(context.timeline, stepId, kind)) {
|
|
2452
|
-
return base(stepId, ...args);
|
|
2453
|
-
}
|
|
2454
|
-
const capturedCtx = import_api.context.active();
|
|
2455
|
-
const startTime = new Date;
|
|
2456
|
-
let result;
|
|
2457
|
-
let originalErr;
|
|
2458
|
-
let thrownError;
|
|
2459
|
-
try {
|
|
2460
|
-
result = await base(stepId, ...args);
|
|
2461
|
-
} catch (err) {
|
|
2462
|
-
originalErr = err;
|
|
2463
|
-
thrownError = err instanceof Error ? err : new Error(String(err));
|
|
2464
|
-
}
|
|
2465
|
-
const span = tracer.startSpan(`${prefix}.step.${kind}`, {
|
|
2466
|
-
startTime,
|
|
2467
|
-
attributes: { "step.id": stepId, "step.type": kind }
|
|
2468
|
-
}, capturedCtx);
|
|
2469
|
-
if (thrownError) {
|
|
2470
|
-
span.recordException(thrownError);
|
|
2471
|
-
span.setStatus({ code: import_api.SpanStatusCode.ERROR, message: thrownError.message });
|
|
2472
|
-
span.end();
|
|
2473
|
-
throw originalErr;
|
|
2474
|
-
}
|
|
2475
|
-
span.setStatus({ code: import_api.SpanStatusCode.OK });
|
|
2476
|
-
span.end();
|
|
2477
|
-
return result;
|
|
2478
|
-
};
|
|
2479
|
-
};
|
|
2480
|
-
return {
|
|
2481
|
-
run: async (stepId, handler) => {
|
|
2482
|
-
if (isCachedHit(context.timeline, stepId, "run")) {
|
|
2483
|
-
return step.run(stepId, handler);
|
|
2484
|
-
}
|
|
2485
|
-
const capturedCtx = import_api.context.active();
|
|
2486
|
-
const startTime = new Date;
|
|
2487
|
-
let result;
|
|
2488
|
-
let originalErr;
|
|
2489
|
-
let thrownError;
|
|
2490
|
-
try {
|
|
2491
|
-
result = await step.run(stepId, handler);
|
|
2492
|
-
} catch (err) {
|
|
2493
|
-
originalErr = err;
|
|
2494
|
-
thrownError = err instanceof Error ? err : new Error(String(err));
|
|
2495
|
-
}
|
|
2496
|
-
if (result === undefined && !thrownError) {
|
|
2497
|
-
return;
|
|
2498
|
-
}
|
|
2499
|
-
const span = tracer.startSpan(`${prefix}.step.run`, {
|
|
2500
|
-
startTime,
|
|
2501
|
-
attributes: { "step.id": stepId, "step.type": "run" }
|
|
2502
|
-
}, capturedCtx);
|
|
2503
|
-
if (thrownError) {
|
|
2504
|
-
span.recordException(thrownError);
|
|
2505
|
-
span.setStatus({ code: import_api.SpanStatusCode.ERROR, message: thrownError.message });
|
|
2506
|
-
span.end();
|
|
2507
|
-
throw originalErr;
|
|
2508
|
-
}
|
|
2509
|
-
span.setStatus({ code: import_api.SpanStatusCode.OK });
|
|
2510
|
-
span.end();
|
|
2511
|
-
return result;
|
|
2512
|
-
},
|
|
2513
|
-
waitFor: wrapVoidish("waitFor", step.waitFor),
|
|
2514
|
-
delay: wrapVoidish("delay", step.delay),
|
|
2515
|
-
sleep: wrapVoidish("delay", step.delay),
|
|
2516
|
-
waitUntil: wrapVoidish("waitUntil", step.waitUntil),
|
|
2517
|
-
pause: wrapVoidish("pause", step.pause),
|
|
2518
|
-
poll: async (stepId, conditionFn, pollOptions) => {
|
|
2519
|
-
const capturedCtx = import_api.context.active();
|
|
2520
|
-
const startTime = new Date;
|
|
2521
|
-
let result;
|
|
2522
|
-
let originalErr;
|
|
2523
|
-
let thrownError;
|
|
2524
|
-
try {
|
|
2525
|
-
result = await step.poll(stepId, conditionFn, pollOptions);
|
|
2526
|
-
} catch (err) {
|
|
2527
|
-
originalErr = err;
|
|
2528
|
-
thrownError = err instanceof Error ? err : new Error(String(err));
|
|
2529
|
-
}
|
|
2530
|
-
const span = tracer.startSpan(`${prefix}.step.poll`, {
|
|
2531
|
-
startTime,
|
|
2532
|
-
attributes: { "step.id": stepId, "step.type": "poll" }
|
|
2533
|
-
}, capturedCtx);
|
|
2534
|
-
if (thrownError) {
|
|
2535
|
-
span.recordException(thrownError);
|
|
2536
|
-
span.setStatus({ code: import_api.SpanStatusCode.ERROR, message: thrownError.message });
|
|
2537
|
-
span.end();
|
|
2538
|
-
throw originalErr;
|
|
2539
|
-
}
|
|
2540
|
-
span.setStatus({ code: import_api.SpanStatusCode.OK });
|
|
2541
|
-
span.end();
|
|
2542
|
-
return result;
|
|
2543
|
-
},
|
|
2544
|
-
invokeChildWorkflow: async (stepId, refOrParams, inputArg, optionsArg) => {
|
|
2545
|
-
if (isCachedHit(context.timeline, stepId, "invokeChildWorkflow")) {
|
|
2546
|
-
return step.invokeChildWorkflow(stepId, refOrParams, inputArg, optionsArg);
|
|
2547
|
-
}
|
|
2548
|
-
const capturedCtx = import_api.context.active();
|
|
2549
|
-
const startTime = new Date;
|
|
2550
|
-
let result;
|
|
2551
|
-
let originalErr;
|
|
2552
|
-
let thrownError;
|
|
2553
|
-
try {
|
|
2554
|
-
result = await step.invokeChildWorkflow(stepId, refOrParams, inputArg, optionsArg);
|
|
2555
|
-
} catch (err) {
|
|
2556
|
-
originalErr = err;
|
|
2557
|
-
thrownError = err instanceof Error ? err : new Error(String(err));
|
|
2558
|
-
}
|
|
2559
|
-
const span = tracer.startSpan(`${prefix}.step.invokeChildWorkflow`, {
|
|
2560
|
-
startTime,
|
|
2561
|
-
attributes: { "step.id": stepId, "step.type": "invokeChildWorkflow" }
|
|
2562
|
-
}, capturedCtx);
|
|
2563
|
-
if (thrownError) {
|
|
2564
|
-
span.recordException(thrownError);
|
|
2565
|
-
span.setStatus({ code: import_api.SpanStatusCode.ERROR, message: thrownError.message });
|
|
2566
|
-
span.end();
|
|
2567
|
-
throw originalErr;
|
|
2568
|
-
}
|
|
2569
|
-
span.setStatus({ code: import_api.SpanStatusCode.OK });
|
|
2570
|
-
span.end();
|
|
2571
|
-
return result;
|
|
2572
|
-
}
|
|
2573
|
-
};
|
|
2574
|
-
},
|
|
2575
|
-
wrap: (context, next) => tracer.startActiveSpan(`${prefix}.workflow.run`, {
|
|
2576
|
-
attributes: {
|
|
2577
|
-
"workflow.id": context.workflowId,
|
|
2578
|
-
"workflow.run_id": context.runId,
|
|
2579
|
-
"workflow.attempt": context.attempt,
|
|
2580
|
-
...context.resourceId ? { "workflow.resource_id": context.resourceId } : {},
|
|
2581
|
-
...extraAttrs ? extraAttrs(context) : {}
|
|
2582
|
-
}
|
|
2583
|
-
}, async (span) => {
|
|
2584
|
-
try {
|
|
2585
|
-
const result = await next();
|
|
2586
|
-
span.setStatus({ code: import_api.SpanStatusCode.OK });
|
|
2587
|
-
return result;
|
|
2588
|
-
} catch (err) {
|
|
2589
|
-
const error = err instanceof Error ? err : new Error(String(err));
|
|
2590
|
-
span.recordException(error);
|
|
2591
|
-
span.setStatus({ code: import_api.SpanStatusCode.ERROR, message: error.message });
|
|
2592
|
-
throw err;
|
|
2593
|
-
} finally {
|
|
2594
|
-
span.end();
|
|
2595
|
-
}
|
|
2596
|
-
})
|
|
2597
|
-
};
|
|
2598
2482
|
}
|
|
2599
2483
|
|
|
2600
|
-
//# debugId=
|
|
2484
|
+
//# debugId=B101AE54CEFCC2C064756E2164756E21
|
|
2601
2485
|
//# sourceMappingURL=index.js.map
|
package/dist/index.d.cts
CHANGED
|
@@ -65,6 +65,7 @@ declare enum WorkflowStatus {
|
|
|
65
65
|
FAILED = "failed",
|
|
66
66
|
CANCELLED = "cancelled"
|
|
67
67
|
}
|
|
68
|
+
type WorkflowRunStats = Record<WorkflowStatus, number>;
|
|
68
69
|
declare enum StepType {
|
|
69
70
|
PAUSE = "pause",
|
|
70
71
|
RUN = "run",
|
|
@@ -349,9 +350,21 @@ declare class WorkflowClient {
|
|
|
349
350
|
hasMore: boolean;
|
|
350
351
|
hasPrev: boolean;
|
|
351
352
|
}>;
|
|
353
|
+
getStats({ resourceId, workflowId }?: {
|
|
354
|
+
resourceId?: string;
|
|
355
|
+
workflowId?: string;
|
|
356
|
+
}): Promise<WorkflowRunStats>;
|
|
352
357
|
private ensureStarted;
|
|
353
358
|
}
|
|
354
359
|
/**
|
|
360
|
+
* True when a re-executed handler will replay `stepId` from `timeline` instead
|
|
361
|
+
* of running it: the step has a recorded output, or it is an
|
|
362
|
+
* `invokeChildWorkflow` step whose child is already bound. Public so plugins
|
|
363
|
+
* (e.g. tracing) can tell replays from real executions without depending on
|
|
364
|
+
* the timeline shape.
|
|
365
|
+
*/
|
|
366
|
+
declare const isStepCached: (timeline: Record<string, unknown>, stepId: string) => boolean;
|
|
367
|
+
/**
|
|
355
368
|
* Create a lightweight workflow reference.
|
|
356
369
|
* Safe to import from `pg-workflows/client` - no engine or handler code.
|
|
357
370
|
*/
|
|
@@ -522,6 +535,10 @@ declare class WorkflowEngine {
|
|
|
522
535
|
hasMore: boolean;
|
|
523
536
|
hasPrev: boolean;
|
|
524
537
|
}>;
|
|
538
|
+
getStats({ resourceId, workflowId }?: {
|
|
539
|
+
resourceId?: string;
|
|
540
|
+
workflowId?: string;
|
|
541
|
+
}): Promise<WorkflowRunStats>;
|
|
525
542
|
}
|
|
526
543
|
import { StandardSchemaV1 as StandardSchemaV12 } from "@standard-schema/spec";
|
|
527
544
|
declare class WorkflowEngineError extends Error {
|
|
@@ -537,14 +554,4 @@ declare class WorkflowRunNotFoundError extends WorkflowEngineError {
|
|
|
537
554
|
declare class WorkflowRunInProgressError extends WorkflowEngineError {
|
|
538
555
|
constructor(workflowId: string, runId?: string);
|
|
539
556
|
}
|
|
540
|
-
|
|
541
|
-
type OtelPluginOptions = {
|
|
542
|
-
/** Tracer to use. Defaults to `trace.getTracer('pg-workflows')`. */
|
|
543
|
-
tracer?: Tracer;
|
|
544
|
-
/** Prefix for all span names. Defaults to `pg_workflows`. */
|
|
545
|
-
spanNamePrefix?: string;
|
|
546
|
-
/** Extra attributes merged onto the workflow.run span. */
|
|
547
|
-
attributes?: (context: WorkflowContext) => Record<string, AttributeValue>;
|
|
548
|
-
};
|
|
549
|
-
declare function otelPlugin(options?: OtelPluginOptions): WorkflowPlugin<StepBaseContext, object>;
|
|
550
|
-
export { workflow, otelPlugin, createWorkflowRef, WorkflowStatus, WorkflowRunProgress, WorkflowRunNotFoundError, WorkflowRunInProgressError, WorkflowRun, WorkflowRef, WorkflowPriority, WorkflowPlugin, WorkflowOptions, WorkflowLogger, WorkflowEngineOptions, WorkflowEngineError, WorkflowEngine, WorkflowDefinition, WorkflowContext, WorkflowClientOptions, WorkflowClient, StepBaseContext, StartWorkflowOptions, ScheduleContext, Schedule, OtelPluginOptions, InputParameters, InferInputParameters, Duration };
|
|
557
|
+
export { workflow, isStepCached, createWorkflowRef, WorkflowStatus, WorkflowRunStats, WorkflowRunProgress, WorkflowRunNotFoundError, WorkflowRunInProgressError, WorkflowRun, WorkflowRef, WorkflowPriority, WorkflowPlugin, WorkflowOptions, WorkflowLogger, WorkflowEngineOptions, WorkflowEngineError, WorkflowEngine, WorkflowDefinition, WorkflowContext, WorkflowClientOptions, WorkflowClient, StepBaseContext, StartWorkflowOptions, ScheduleContext, Schedule, InputParameters, InferInputParameters, Duration };
|
package/dist/index.d.ts
CHANGED
|
@@ -65,6 +65,7 @@ declare enum WorkflowStatus {
|
|
|
65
65
|
FAILED = "failed",
|
|
66
66
|
CANCELLED = "cancelled"
|
|
67
67
|
}
|
|
68
|
+
type WorkflowRunStats = Record<WorkflowStatus, number>;
|
|
68
69
|
declare enum StepType {
|
|
69
70
|
PAUSE = "pause",
|
|
70
71
|
RUN = "run",
|
|
@@ -349,9 +350,21 @@ declare class WorkflowClient {
|
|
|
349
350
|
hasMore: boolean;
|
|
350
351
|
hasPrev: boolean;
|
|
351
352
|
}>;
|
|
353
|
+
getStats({ resourceId, workflowId }?: {
|
|
354
|
+
resourceId?: string;
|
|
355
|
+
workflowId?: string;
|
|
356
|
+
}): Promise<WorkflowRunStats>;
|
|
352
357
|
private ensureStarted;
|
|
353
358
|
}
|
|
354
359
|
/**
|
|
360
|
+
* True when a re-executed handler will replay `stepId` from `timeline` instead
|
|
361
|
+
* of running it: the step has a recorded output, or it is an
|
|
362
|
+
* `invokeChildWorkflow` step whose child is already bound. Public so plugins
|
|
363
|
+
* (e.g. tracing) can tell replays from real executions without depending on
|
|
364
|
+
* the timeline shape.
|
|
365
|
+
*/
|
|
366
|
+
declare const isStepCached: (timeline: Record<string, unknown>, stepId: string) => boolean;
|
|
367
|
+
/**
|
|
355
368
|
* Create a lightweight workflow reference.
|
|
356
369
|
* Safe to import from `pg-workflows/client` - no engine or handler code.
|
|
357
370
|
*/
|
|
@@ -522,6 +535,10 @@ declare class WorkflowEngine {
|
|
|
522
535
|
hasMore: boolean;
|
|
523
536
|
hasPrev: boolean;
|
|
524
537
|
}>;
|
|
538
|
+
getStats({ resourceId, workflowId }?: {
|
|
539
|
+
resourceId?: string;
|
|
540
|
+
workflowId?: string;
|
|
541
|
+
}): Promise<WorkflowRunStats>;
|
|
525
542
|
}
|
|
526
543
|
import { StandardSchemaV1 as StandardSchemaV12 } from "@standard-schema/spec";
|
|
527
544
|
declare class WorkflowEngineError extends Error {
|
|
@@ -537,14 +554,4 @@ declare class WorkflowRunNotFoundError extends WorkflowEngineError {
|
|
|
537
554
|
declare class WorkflowRunInProgressError extends WorkflowEngineError {
|
|
538
555
|
constructor(workflowId: string, runId?: string);
|
|
539
556
|
}
|
|
540
|
-
|
|
541
|
-
type OtelPluginOptions = {
|
|
542
|
-
/** Tracer to use. Defaults to `trace.getTracer('pg-workflows')`. */
|
|
543
|
-
tracer?: Tracer;
|
|
544
|
-
/** Prefix for all span names. Defaults to `pg_workflows`. */
|
|
545
|
-
spanNamePrefix?: string;
|
|
546
|
-
/** Extra attributes merged onto the workflow.run span. */
|
|
547
|
-
attributes?: (context: WorkflowContext) => Record<string, AttributeValue>;
|
|
548
|
-
};
|
|
549
|
-
declare function otelPlugin(options?: OtelPluginOptions): WorkflowPlugin<StepBaseContext, object>;
|
|
550
|
-
export { workflow, otelPlugin, createWorkflowRef, WorkflowStatus, WorkflowRunProgress, WorkflowRunNotFoundError, WorkflowRunInProgressError, WorkflowRun, WorkflowRef, WorkflowPriority, WorkflowPlugin, WorkflowOptions, WorkflowLogger, WorkflowEngineOptions, WorkflowEngineError, WorkflowEngine, WorkflowDefinition, WorkflowContext, WorkflowClientOptions, WorkflowClient, StepBaseContext, StartWorkflowOptions, ScheduleContext, Schedule, OtelPluginOptions, InputParameters, InferInputParameters, Duration };
|
|
557
|
+
export { workflow, isStepCached, createWorkflowRef, WorkflowStatus, WorkflowRunStats, WorkflowRunProgress, WorkflowRunNotFoundError, WorkflowRunInProgressError, WorkflowRun, WorkflowRef, WorkflowPriority, WorkflowPlugin, WorkflowOptions, WorkflowLogger, WorkflowEngineOptions, WorkflowEngineError, WorkflowEngine, WorkflowDefinition, WorkflowContext, WorkflowClientOptions, WorkflowClient, StepBaseContext, StartWorkflowOptions, ScheduleContext, Schedule, InputParameters, InferInputParameters, Duration };
|
package/dist/index.js
CHANGED
|
@@ -13,10 +13,12 @@ import {
|
|
|
13
13
|
createWorkflowRef,
|
|
14
14
|
getWorkflowLastRun,
|
|
15
15
|
getWorkflowRun,
|
|
16
|
+
getWorkflowRunStats,
|
|
16
17
|
getWorkflowRuns,
|
|
17
18
|
insertWorkflowRun,
|
|
18
19
|
invokeChildWorkflowTimelineKey,
|
|
19
20
|
isInvokeChildWorkflowTimelineEntry,
|
|
21
|
+
isStepCached,
|
|
20
22
|
resolvePriority,
|
|
21
23
|
runMigrations,
|
|
22
24
|
scheduleQueueNameFor,
|
|
@@ -26,7 +28,7 @@ import {
|
|
|
26
28
|
waitForTimelineKey,
|
|
27
29
|
withPostgresTransaction,
|
|
28
30
|
workflow
|
|
29
|
-
} from "./shared/chunk-
|
|
31
|
+
} from "./shared/chunk-d204nxd5.js";
|
|
30
32
|
// src/engine.ts
|
|
31
33
|
import { merge } from "es-toolkit";
|
|
32
34
|
import pg from "pg";
|
|
@@ -1397,184 +1399,19 @@ ${error.stack}` : String(error)
|
|
|
1397
1399
|
workflowId
|
|
1398
1400
|
}, this.db);
|
|
1399
1401
|
}
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
function isCachedHit(timeline, stepId, kind) {
|
|
1409
|
-
const entry = timeline[stepId];
|
|
1410
|
-
if (entry && typeof entry === "object" && "output" in entry && entry.output !== undefined) {
|
|
1411
|
-
return true;
|
|
1412
|
-
}
|
|
1413
|
-
if (kind === "invokeChildWorkflow" && timeline[invokeChildWorkflowTimelineKey(stepId)]) {
|
|
1414
|
-
return true;
|
|
1402
|
+
async getStats({
|
|
1403
|
+
resourceId,
|
|
1404
|
+
workflowId
|
|
1405
|
+
} = {}) {
|
|
1406
|
+
if (workflowId)
|
|
1407
|
+
validateWorkflowId(workflowId);
|
|
1408
|
+
validateResourceId(resourceId);
|
|
1409
|
+
return getWorkflowRunStats({ resourceId, workflowId }, this.db);
|
|
1415
1410
|
}
|
|
1416
|
-
return false;
|
|
1417
|
-
}
|
|
1418
|
-
function otelPlugin(options = {}) {
|
|
1419
|
-
const tracer = options.tracer ?? trace.getTracer("pg-workflows");
|
|
1420
|
-
const prefix = options.spanNamePrefix ?? DEFAULT_PREFIX;
|
|
1421
|
-
const extraAttrs = options.attributes;
|
|
1422
|
-
return {
|
|
1423
|
-
name: "opentelemetry",
|
|
1424
|
-
methods: (step, context) => {
|
|
1425
|
-
const wrapVoidish = (kind, base) => {
|
|
1426
|
-
return async (stepId, ...args) => {
|
|
1427
|
-
if (isCachedHit(context.timeline, stepId, kind)) {
|
|
1428
|
-
return base(stepId, ...args);
|
|
1429
|
-
}
|
|
1430
|
-
const capturedCtx = otelContext.active();
|
|
1431
|
-
const startTime = new Date;
|
|
1432
|
-
let result;
|
|
1433
|
-
let originalErr;
|
|
1434
|
-
let thrownError;
|
|
1435
|
-
try {
|
|
1436
|
-
result = await base(stepId, ...args);
|
|
1437
|
-
} catch (err) {
|
|
1438
|
-
originalErr = err;
|
|
1439
|
-
thrownError = err instanceof Error ? err : new Error(String(err));
|
|
1440
|
-
}
|
|
1441
|
-
const span = tracer.startSpan(`${prefix}.step.${kind}`, {
|
|
1442
|
-
startTime,
|
|
1443
|
-
attributes: { "step.id": stepId, "step.type": kind }
|
|
1444
|
-
}, capturedCtx);
|
|
1445
|
-
if (thrownError) {
|
|
1446
|
-
span.recordException(thrownError);
|
|
1447
|
-
span.setStatus({ code: SpanStatusCode.ERROR, message: thrownError.message });
|
|
1448
|
-
span.end();
|
|
1449
|
-
throw originalErr;
|
|
1450
|
-
}
|
|
1451
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
1452
|
-
span.end();
|
|
1453
|
-
return result;
|
|
1454
|
-
};
|
|
1455
|
-
};
|
|
1456
|
-
return {
|
|
1457
|
-
run: async (stepId, handler) => {
|
|
1458
|
-
if (isCachedHit(context.timeline, stepId, "run")) {
|
|
1459
|
-
return step.run(stepId, handler);
|
|
1460
|
-
}
|
|
1461
|
-
const capturedCtx = otelContext.active();
|
|
1462
|
-
const startTime = new Date;
|
|
1463
|
-
let result;
|
|
1464
|
-
let originalErr;
|
|
1465
|
-
let thrownError;
|
|
1466
|
-
try {
|
|
1467
|
-
result = await step.run(stepId, handler);
|
|
1468
|
-
} catch (err) {
|
|
1469
|
-
originalErr = err;
|
|
1470
|
-
thrownError = err instanceof Error ? err : new Error(String(err));
|
|
1471
|
-
}
|
|
1472
|
-
if (result === undefined && !thrownError) {
|
|
1473
|
-
return;
|
|
1474
|
-
}
|
|
1475
|
-
const span = tracer.startSpan(`${prefix}.step.run`, {
|
|
1476
|
-
startTime,
|
|
1477
|
-
attributes: { "step.id": stepId, "step.type": "run" }
|
|
1478
|
-
}, capturedCtx);
|
|
1479
|
-
if (thrownError) {
|
|
1480
|
-
span.recordException(thrownError);
|
|
1481
|
-
span.setStatus({ code: SpanStatusCode.ERROR, message: thrownError.message });
|
|
1482
|
-
span.end();
|
|
1483
|
-
throw originalErr;
|
|
1484
|
-
}
|
|
1485
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
1486
|
-
span.end();
|
|
1487
|
-
return result;
|
|
1488
|
-
},
|
|
1489
|
-
waitFor: wrapVoidish("waitFor", step.waitFor),
|
|
1490
|
-
delay: wrapVoidish("delay", step.delay),
|
|
1491
|
-
sleep: wrapVoidish("delay", step.delay),
|
|
1492
|
-
waitUntil: wrapVoidish("waitUntil", step.waitUntil),
|
|
1493
|
-
pause: wrapVoidish("pause", step.pause),
|
|
1494
|
-
poll: async (stepId, conditionFn, pollOptions) => {
|
|
1495
|
-
const capturedCtx = otelContext.active();
|
|
1496
|
-
const startTime = new Date;
|
|
1497
|
-
let result;
|
|
1498
|
-
let originalErr;
|
|
1499
|
-
let thrownError;
|
|
1500
|
-
try {
|
|
1501
|
-
result = await step.poll(stepId, conditionFn, pollOptions);
|
|
1502
|
-
} catch (err) {
|
|
1503
|
-
originalErr = err;
|
|
1504
|
-
thrownError = err instanceof Error ? err : new Error(String(err));
|
|
1505
|
-
}
|
|
1506
|
-
const span = tracer.startSpan(`${prefix}.step.poll`, {
|
|
1507
|
-
startTime,
|
|
1508
|
-
attributes: { "step.id": stepId, "step.type": "poll" }
|
|
1509
|
-
}, capturedCtx);
|
|
1510
|
-
if (thrownError) {
|
|
1511
|
-
span.recordException(thrownError);
|
|
1512
|
-
span.setStatus({ code: SpanStatusCode.ERROR, message: thrownError.message });
|
|
1513
|
-
span.end();
|
|
1514
|
-
throw originalErr;
|
|
1515
|
-
}
|
|
1516
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
1517
|
-
span.end();
|
|
1518
|
-
return result;
|
|
1519
|
-
},
|
|
1520
|
-
invokeChildWorkflow: async (stepId, refOrParams, inputArg, optionsArg) => {
|
|
1521
|
-
if (isCachedHit(context.timeline, stepId, "invokeChildWorkflow")) {
|
|
1522
|
-
return step.invokeChildWorkflow(stepId, refOrParams, inputArg, optionsArg);
|
|
1523
|
-
}
|
|
1524
|
-
const capturedCtx = otelContext.active();
|
|
1525
|
-
const startTime = new Date;
|
|
1526
|
-
let result;
|
|
1527
|
-
let originalErr;
|
|
1528
|
-
let thrownError;
|
|
1529
|
-
try {
|
|
1530
|
-
result = await step.invokeChildWorkflow(stepId, refOrParams, inputArg, optionsArg);
|
|
1531
|
-
} catch (err) {
|
|
1532
|
-
originalErr = err;
|
|
1533
|
-
thrownError = err instanceof Error ? err : new Error(String(err));
|
|
1534
|
-
}
|
|
1535
|
-
const span = tracer.startSpan(`${prefix}.step.invokeChildWorkflow`, {
|
|
1536
|
-
startTime,
|
|
1537
|
-
attributes: { "step.id": stepId, "step.type": "invokeChildWorkflow" }
|
|
1538
|
-
}, capturedCtx);
|
|
1539
|
-
if (thrownError) {
|
|
1540
|
-
span.recordException(thrownError);
|
|
1541
|
-
span.setStatus({ code: SpanStatusCode.ERROR, message: thrownError.message });
|
|
1542
|
-
span.end();
|
|
1543
|
-
throw originalErr;
|
|
1544
|
-
}
|
|
1545
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
1546
|
-
span.end();
|
|
1547
|
-
return result;
|
|
1548
|
-
}
|
|
1549
|
-
};
|
|
1550
|
-
},
|
|
1551
|
-
wrap: (context, next) => tracer.startActiveSpan(`${prefix}.workflow.run`, {
|
|
1552
|
-
attributes: {
|
|
1553
|
-
"workflow.id": context.workflowId,
|
|
1554
|
-
"workflow.run_id": context.runId,
|
|
1555
|
-
"workflow.attempt": context.attempt,
|
|
1556
|
-
...context.resourceId ? { "workflow.resource_id": context.resourceId } : {},
|
|
1557
|
-
...extraAttrs ? extraAttrs(context) : {}
|
|
1558
|
-
}
|
|
1559
|
-
}, async (span) => {
|
|
1560
|
-
try {
|
|
1561
|
-
const result = await next();
|
|
1562
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
1563
|
-
return result;
|
|
1564
|
-
} catch (err) {
|
|
1565
|
-
const error = err instanceof Error ? err : new Error(String(err));
|
|
1566
|
-
span.recordException(error);
|
|
1567
|
-
span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
|
|
1568
|
-
throw err;
|
|
1569
|
-
} finally {
|
|
1570
|
-
span.end();
|
|
1571
|
-
}
|
|
1572
|
-
})
|
|
1573
|
-
};
|
|
1574
1411
|
}
|
|
1575
1412
|
export {
|
|
1576
1413
|
workflow,
|
|
1577
|
-
|
|
1414
|
+
isStepCached,
|
|
1578
1415
|
createWorkflowRef,
|
|
1579
1416
|
WorkflowStatus,
|
|
1580
1417
|
WorkflowRunNotFoundError,
|
|
@@ -1584,5 +1421,5 @@ export {
|
|
|
1584
1421
|
WorkflowClient
|
|
1585
1422
|
};
|
|
1586
1423
|
|
|
1587
|
-
//# debugId=
|
|
1424
|
+
//# debugId=5FDB649CAAD8594E64756E2164756E21
|
|
1588
1425
|
//# sourceMappingURL=index.js.map
|