pg-workflows 0.14.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 +227 -93
- package/dist/client.entry.d.cts +31 -1
- package/dist/client.entry.d.ts +31 -1
- package/dist/client.entry.js +4 -2
- package/dist/client.entry.js.map +10 -10
- package/dist/index.cjs +249 -269
- package/dist/index.d.cts +44 -11
- package/dist/index.d.ts +44 -11
- package/dist/index.js +29 -182
- package/dist/index.js.map +12 -13
- package/dist/shared/{chunk-w3qcrrwx.js → chunk-d204nxd5.js} +167 -36
- package/dist/shared/chunk-d204nxd5.js.map +17 -0
- package/package.json +14 -25
- package/LICENSE +0 -22
- package/README.md +0 -214
- package/dist/shared/chunk-w3qcrrwx.js.map +0 -17
package/dist/index.d.cts
CHANGED
|
@@ -20,6 +20,13 @@ type WorkflowRun = {
|
|
|
20
20
|
maxRetries: number;
|
|
21
21
|
/** Resolved scheduling priority (pg-boss integer; higher runs first). */
|
|
22
22
|
priority: number;
|
|
23
|
+
/**
|
|
24
|
+
* When true, this run participates in the per-workflow-ID uniqueness
|
|
25
|
+
* constraint: no other pending or running singleton run of the same
|
|
26
|
+
* workflow ID may exist at the same time. Paused, completed, failed, and
|
|
27
|
+
* cancelled runs release the slot.
|
|
28
|
+
*/
|
|
29
|
+
singleton: boolean;
|
|
23
30
|
jobId: string | null;
|
|
24
31
|
idempotencyKey: string | null;
|
|
25
32
|
parentRunId: string | null;
|
|
@@ -58,6 +65,7 @@ declare enum WorkflowStatus {
|
|
|
58
65
|
FAILED = "failed",
|
|
59
66
|
CANCELLED = "cancelled"
|
|
60
67
|
}
|
|
68
|
+
type WorkflowRunStats = Record<WorkflowStatus, number>;
|
|
61
69
|
declare enum StepType {
|
|
62
70
|
PAUSE = "pause",
|
|
63
71
|
RUN = "run",
|
|
@@ -76,6 +84,12 @@ type StartWorkflowOptions = {
|
|
|
76
84
|
expireInSeconds?: number;
|
|
77
85
|
idempotencyKey?: string;
|
|
78
86
|
priority?: WorkflowPriority;
|
|
87
|
+
/**
|
|
88
|
+
* Client-side counterpart of `workflow(..., { singleton: true })`.
|
|
89
|
+
* The engine reads this from the registered definition; pass it here when
|
|
90
|
+
* starting from `WorkflowClient` so the uniqueness constraint applies.
|
|
91
|
+
*/
|
|
92
|
+
singleton?: boolean;
|
|
79
93
|
};
|
|
80
94
|
type WorkflowOptions<I extends InputParameters> = {
|
|
81
95
|
timeout?: number;
|
|
@@ -83,6 +97,12 @@ type WorkflowOptions<I extends InputParameters> = {
|
|
|
83
97
|
inputSchema?: I;
|
|
84
98
|
priority?: WorkflowPriority;
|
|
85
99
|
/**
|
|
100
|
+
* When true, at most one pending or running run of this workflow ID may exist.
|
|
101
|
+
* A second `startWorkflow` throws `WorkflowRunInProgressError` until the
|
|
102
|
+
* current run pauses, completes, fails, or is cancelled.
|
|
103
|
+
*/
|
|
104
|
+
singleton?: boolean;
|
|
105
|
+
/**
|
|
86
106
|
* Recurring schedule. Accepts a cron expression (`'0 9 * * 1-5'`),
|
|
87
107
|
* a duration string (`'5m'`, `'1 hour'`), or a `DurationObject`.
|
|
88
108
|
*/
|
|
@@ -190,6 +210,7 @@ type WorkflowDefinition<TInput extends InputParameters = InputParameters> = {
|
|
|
190
210
|
timeout?: number;
|
|
191
211
|
retries?: number;
|
|
192
212
|
priority?: WorkflowPriority;
|
|
213
|
+
singleton?: boolean;
|
|
193
214
|
schedule?: Schedule;
|
|
194
215
|
timezone?: string;
|
|
195
216
|
plugins?: WorkflowPlugin[];
|
|
@@ -216,6 +237,7 @@ interface WorkflowFactory<TStepExt = object> {
|
|
|
216
237
|
TOutput = unknown
|
|
217
238
|
>(id: string, options?: {
|
|
218
239
|
inputSchema?: TInput;
|
|
240
|
+
singleton?: boolean;
|
|
219
241
|
}): WorkflowRef<TInput, TOutput>;
|
|
220
242
|
}
|
|
221
243
|
/**
|
|
@@ -232,6 +254,7 @@ interface WorkflowRef<
|
|
|
232
254
|
(handler: (context: WorkflowContext<TInput, StepBaseContext>) => Promise<unknown>, options?: Omit<WorkflowOptions<TInput>, "inputSchema">): WorkflowDefinition<TInput>;
|
|
233
255
|
readonly id: string;
|
|
234
256
|
readonly inputSchema?: TInput;
|
|
257
|
+
readonly singleton?: boolean;
|
|
235
258
|
}
|
|
236
259
|
type WorkflowRunProgress = WorkflowRun & {
|
|
237
260
|
completionPercentage: number;
|
|
@@ -327,9 +350,21 @@ declare class WorkflowClient {
|
|
|
327
350
|
hasMore: boolean;
|
|
328
351
|
hasPrev: boolean;
|
|
329
352
|
}>;
|
|
353
|
+
getStats({ resourceId, workflowId }?: {
|
|
354
|
+
resourceId?: string;
|
|
355
|
+
workflowId?: string;
|
|
356
|
+
}): Promise<WorkflowRunStats>;
|
|
330
357
|
private ensureStarted;
|
|
331
358
|
}
|
|
332
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
|
+
/**
|
|
333
368
|
* Create a lightweight workflow reference.
|
|
334
369
|
* Safe to import from `pg-workflows/client` - no engine or handler code.
|
|
335
370
|
*/
|
|
@@ -338,6 +373,7 @@ declare function createWorkflowRef<
|
|
|
338
373
|
TInput extends InputParameters = InputParameters
|
|
339
374
|
>(id: string, options?: {
|
|
340
375
|
inputSchema?: TInput;
|
|
376
|
+
singleton?: boolean;
|
|
341
377
|
}): WorkflowRef<TInput, TOutput>;
|
|
342
378
|
declare const workflow: WorkflowFactory;
|
|
343
379
|
import pg2 from "pg";
|
|
@@ -499,6 +535,10 @@ declare class WorkflowEngine {
|
|
|
499
535
|
hasMore: boolean;
|
|
500
536
|
hasPrev: boolean;
|
|
501
537
|
}>;
|
|
538
|
+
getStats({ resourceId, workflowId }?: {
|
|
539
|
+
resourceId?: string;
|
|
540
|
+
workflowId?: string;
|
|
541
|
+
}): Promise<WorkflowRunStats>;
|
|
502
542
|
}
|
|
503
543
|
import { StandardSchemaV1 as StandardSchemaV12 } from "@standard-schema/spec";
|
|
504
544
|
declare class WorkflowEngineError extends Error {
|
|
@@ -511,14 +551,7 @@ declare class WorkflowEngineError extends Error {
|
|
|
511
551
|
declare class WorkflowRunNotFoundError extends WorkflowEngineError {
|
|
512
552
|
constructor(runId?: string, workflowId?: string);
|
|
513
553
|
}
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
/** Prefix for all span names. Defaults to `pg_workflows`. */
|
|
519
|
-
spanNamePrefix?: string;
|
|
520
|
-
/** Extra attributes merged onto the workflow.run span. */
|
|
521
|
-
attributes?: (context: WorkflowContext) => Record<string, AttributeValue>;
|
|
522
|
-
};
|
|
523
|
-
declare function otelPlugin(options?: OtelPluginOptions): WorkflowPlugin<StepBaseContext, object>;
|
|
524
|
-
export { workflow, otelPlugin, createWorkflowRef, WorkflowStatus, WorkflowRunProgress, WorkflowRunNotFoundError, WorkflowRun, WorkflowRef, WorkflowPriority, WorkflowPlugin, WorkflowOptions, WorkflowLogger, WorkflowEngineOptions, WorkflowEngineError, WorkflowEngine, WorkflowDefinition, WorkflowContext, WorkflowClientOptions, WorkflowClient, StepBaseContext, StartWorkflowOptions, ScheduleContext, Schedule, OtelPluginOptions, InputParameters, InferInputParameters, Duration };
|
|
554
|
+
declare class WorkflowRunInProgressError extends WorkflowEngineError {
|
|
555
|
+
constructor(workflowId: string, runId?: string);
|
|
556
|
+
}
|
|
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
|
@@ -20,6 +20,13 @@ type WorkflowRun = {
|
|
|
20
20
|
maxRetries: number;
|
|
21
21
|
/** Resolved scheduling priority (pg-boss integer; higher runs first). */
|
|
22
22
|
priority: number;
|
|
23
|
+
/**
|
|
24
|
+
* When true, this run participates in the per-workflow-ID uniqueness
|
|
25
|
+
* constraint: no other pending or running singleton run of the same
|
|
26
|
+
* workflow ID may exist at the same time. Paused, completed, failed, and
|
|
27
|
+
* cancelled runs release the slot.
|
|
28
|
+
*/
|
|
29
|
+
singleton: boolean;
|
|
23
30
|
jobId: string | null;
|
|
24
31
|
idempotencyKey: string | null;
|
|
25
32
|
parentRunId: string | null;
|
|
@@ -58,6 +65,7 @@ declare enum WorkflowStatus {
|
|
|
58
65
|
FAILED = "failed",
|
|
59
66
|
CANCELLED = "cancelled"
|
|
60
67
|
}
|
|
68
|
+
type WorkflowRunStats = Record<WorkflowStatus, number>;
|
|
61
69
|
declare enum StepType {
|
|
62
70
|
PAUSE = "pause",
|
|
63
71
|
RUN = "run",
|
|
@@ -76,6 +84,12 @@ type StartWorkflowOptions = {
|
|
|
76
84
|
expireInSeconds?: number;
|
|
77
85
|
idempotencyKey?: string;
|
|
78
86
|
priority?: WorkflowPriority;
|
|
87
|
+
/**
|
|
88
|
+
* Client-side counterpart of `workflow(..., { singleton: true })`.
|
|
89
|
+
* The engine reads this from the registered definition; pass it here when
|
|
90
|
+
* starting from `WorkflowClient` so the uniqueness constraint applies.
|
|
91
|
+
*/
|
|
92
|
+
singleton?: boolean;
|
|
79
93
|
};
|
|
80
94
|
type WorkflowOptions<I extends InputParameters> = {
|
|
81
95
|
timeout?: number;
|
|
@@ -83,6 +97,12 @@ type WorkflowOptions<I extends InputParameters> = {
|
|
|
83
97
|
inputSchema?: I;
|
|
84
98
|
priority?: WorkflowPriority;
|
|
85
99
|
/**
|
|
100
|
+
* When true, at most one pending or running run of this workflow ID may exist.
|
|
101
|
+
* A second `startWorkflow` throws `WorkflowRunInProgressError` until the
|
|
102
|
+
* current run pauses, completes, fails, or is cancelled.
|
|
103
|
+
*/
|
|
104
|
+
singleton?: boolean;
|
|
105
|
+
/**
|
|
86
106
|
* Recurring schedule. Accepts a cron expression (`'0 9 * * 1-5'`),
|
|
87
107
|
* a duration string (`'5m'`, `'1 hour'`), or a `DurationObject`.
|
|
88
108
|
*/
|
|
@@ -190,6 +210,7 @@ type WorkflowDefinition<TInput extends InputParameters = InputParameters> = {
|
|
|
190
210
|
timeout?: number;
|
|
191
211
|
retries?: number;
|
|
192
212
|
priority?: WorkflowPriority;
|
|
213
|
+
singleton?: boolean;
|
|
193
214
|
schedule?: Schedule;
|
|
194
215
|
timezone?: string;
|
|
195
216
|
plugins?: WorkflowPlugin[];
|
|
@@ -216,6 +237,7 @@ interface WorkflowFactory<TStepExt = object> {
|
|
|
216
237
|
TOutput = unknown
|
|
217
238
|
>(id: string, options?: {
|
|
218
239
|
inputSchema?: TInput;
|
|
240
|
+
singleton?: boolean;
|
|
219
241
|
}): WorkflowRef<TInput, TOutput>;
|
|
220
242
|
}
|
|
221
243
|
/**
|
|
@@ -232,6 +254,7 @@ interface WorkflowRef<
|
|
|
232
254
|
(handler: (context: WorkflowContext<TInput, StepBaseContext>) => Promise<unknown>, options?: Omit<WorkflowOptions<TInput>, "inputSchema">): WorkflowDefinition<TInput>;
|
|
233
255
|
readonly id: string;
|
|
234
256
|
readonly inputSchema?: TInput;
|
|
257
|
+
readonly singleton?: boolean;
|
|
235
258
|
}
|
|
236
259
|
type WorkflowRunProgress = WorkflowRun & {
|
|
237
260
|
completionPercentage: number;
|
|
@@ -327,9 +350,21 @@ declare class WorkflowClient {
|
|
|
327
350
|
hasMore: boolean;
|
|
328
351
|
hasPrev: boolean;
|
|
329
352
|
}>;
|
|
353
|
+
getStats({ resourceId, workflowId }?: {
|
|
354
|
+
resourceId?: string;
|
|
355
|
+
workflowId?: string;
|
|
356
|
+
}): Promise<WorkflowRunStats>;
|
|
330
357
|
private ensureStarted;
|
|
331
358
|
}
|
|
332
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
|
+
/**
|
|
333
368
|
* Create a lightweight workflow reference.
|
|
334
369
|
* Safe to import from `pg-workflows/client` - no engine or handler code.
|
|
335
370
|
*/
|
|
@@ -338,6 +373,7 @@ declare function createWorkflowRef<
|
|
|
338
373
|
TInput extends InputParameters = InputParameters
|
|
339
374
|
>(id: string, options?: {
|
|
340
375
|
inputSchema?: TInput;
|
|
376
|
+
singleton?: boolean;
|
|
341
377
|
}): WorkflowRef<TInput, TOutput>;
|
|
342
378
|
declare const workflow: WorkflowFactory;
|
|
343
379
|
import pg2 from "pg";
|
|
@@ -499,6 +535,10 @@ declare class WorkflowEngine {
|
|
|
499
535
|
hasMore: boolean;
|
|
500
536
|
hasPrev: boolean;
|
|
501
537
|
}>;
|
|
538
|
+
getStats({ resourceId, workflowId }?: {
|
|
539
|
+
resourceId?: string;
|
|
540
|
+
workflowId?: string;
|
|
541
|
+
}): Promise<WorkflowRunStats>;
|
|
502
542
|
}
|
|
503
543
|
import { StandardSchemaV1 as StandardSchemaV12 } from "@standard-schema/spec";
|
|
504
544
|
declare class WorkflowEngineError extends Error {
|
|
@@ -511,14 +551,7 @@ declare class WorkflowEngineError extends Error {
|
|
|
511
551
|
declare class WorkflowRunNotFoundError extends WorkflowEngineError {
|
|
512
552
|
constructor(runId?: string, workflowId?: string);
|
|
513
553
|
}
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
/** Prefix for all span names. Defaults to `pg_workflows`. */
|
|
519
|
-
spanNamePrefix?: string;
|
|
520
|
-
/** Extra attributes merged onto the workflow.run span. */
|
|
521
|
-
attributes?: (context: WorkflowContext) => Record<string, AttributeValue>;
|
|
522
|
-
};
|
|
523
|
-
declare function otelPlugin(options?: OtelPluginOptions): WorkflowPlugin<StepBaseContext, object>;
|
|
524
|
-
export { workflow, otelPlugin, createWorkflowRef, WorkflowStatus, WorkflowRunProgress, WorkflowRunNotFoundError, WorkflowRun, WorkflowRef, WorkflowPriority, WorkflowPlugin, WorkflowOptions, WorkflowLogger, WorkflowEngineOptions, WorkflowEngineError, WorkflowEngine, WorkflowDefinition, WorkflowContext, WorkflowClientOptions, WorkflowClient, StepBaseContext, StartWorkflowOptions, ScheduleContext, Schedule, OtelPluginOptions, InputParameters, InferInputParameters, Duration };
|
|
554
|
+
declare class WorkflowRunInProgressError extends WorkflowEngineError {
|
|
555
|
+
constructor(workflowId: string, runId?: string);
|
|
556
|
+
}
|
|
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
|
@@ -6,15 +6,19 @@ import {
|
|
|
6
6
|
WORKFLOW_RUN_QUEUE_NAME,
|
|
7
7
|
WorkflowClient,
|
|
8
8
|
WorkflowEngineError,
|
|
9
|
+
WorkflowRunInProgressError,
|
|
9
10
|
WorkflowRunNotFoundError,
|
|
10
11
|
WorkflowStatus,
|
|
12
|
+
assertSingletonSlotAvailable,
|
|
11
13
|
createWorkflowRef,
|
|
12
14
|
getWorkflowLastRun,
|
|
13
15
|
getWorkflowRun,
|
|
16
|
+
getWorkflowRunStats,
|
|
14
17
|
getWorkflowRuns,
|
|
15
18
|
insertWorkflowRun,
|
|
16
19
|
invokeChildWorkflowTimelineKey,
|
|
17
20
|
isInvokeChildWorkflowTimelineEntry,
|
|
21
|
+
isStepCached,
|
|
18
22
|
resolvePriority,
|
|
19
23
|
runMigrations,
|
|
20
24
|
scheduleQueueNameFor,
|
|
@@ -24,7 +28,7 @@ import {
|
|
|
24
28
|
waitForTimelineKey,
|
|
25
29
|
withPostgresTransaction,
|
|
26
30
|
workflow
|
|
27
|
-
} from "./shared/chunk-
|
|
31
|
+
} from "./shared/chunk-d204nxd5.js";
|
|
28
32
|
// src/engine.ts
|
|
29
33
|
import { merge } from "es-toolkit";
|
|
30
34
|
import pg from "pg";
|
|
@@ -225,11 +229,10 @@ class WorkflowEngine {
|
|
|
225
229
|
const db = {
|
|
226
230
|
executeSql: (text, values) => this.pool.query(text, values)
|
|
227
231
|
};
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
}
|
|
232
|
+
this.boss = boss ?? new PgBoss({ db, schema: DEFAULT_PGBOSS_SCHEMA });
|
|
233
|
+
this.boss.on("error", (error) => {
|
|
234
|
+
this.logger.error("pg-boss error", error);
|
|
235
|
+
});
|
|
233
236
|
this.db = this.boss.getDb();
|
|
234
237
|
}
|
|
235
238
|
async start(asEngine = true, {
|
|
@@ -283,6 +286,10 @@ class WorkflowEngine {
|
|
|
283
286
|
try {
|
|
284
287
|
await this.createWorkflowRun({ workflowId, input: {}, scheduledAt });
|
|
285
288
|
} catch (error) {
|
|
289
|
+
if (error instanceof WorkflowRunInProgressError) {
|
|
290
|
+
this.logger.log(`Skipping schedule fire for "${workflowId}": a run is already in progress`, { workflowId, runId: error.runId });
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
286
293
|
this.logger.error(`Schedule fire failed to start a run for workflow "${workflowId}"`, error instanceof Error ? error : new Error(String(error)), { workflowId });
|
|
287
294
|
throw error;
|
|
288
295
|
}
|
|
@@ -432,7 +439,8 @@ class WorkflowEngine {
|
|
|
432
439
|
parentRunId,
|
|
433
440
|
parentStepId,
|
|
434
441
|
parentResourceId,
|
|
435
|
-
scheduledAt
|
|
442
|
+
scheduledAt,
|
|
443
|
+
singleton: workflow2.singleton === true || options?.singleton === true
|
|
436
444
|
}, targetDb);
|
|
437
445
|
const insertAndEnqueue = async (targetDb) => {
|
|
438
446
|
const result = await insertRun(targetDb);
|
|
@@ -591,6 +599,9 @@ class WorkflowEngine {
|
|
|
591
599
|
}) {
|
|
592
600
|
await this.checkIfHasStarted();
|
|
593
601
|
const run = await this.getRun({ runId, resourceId });
|
|
602
|
+
if (run.singleton) {
|
|
603
|
+
await assertSingletonSlotAvailable({ workflowId: run.workflowId, exceptRunId: run.id }, this.db);
|
|
604
|
+
}
|
|
594
605
|
const jobResourceId = resourceId ?? run.resourceId ?? undefined;
|
|
595
606
|
const job = {
|
|
596
607
|
runId: run.id,
|
|
@@ -1388,191 +1399,27 @@ ${error.stack}` : String(error)
|
|
|
1388
1399
|
workflowId
|
|
1389
1400
|
}, this.db);
|
|
1390
1401
|
}
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
function isCachedHit(timeline, stepId, kind) {
|
|
1400
|
-
const entry = timeline[stepId];
|
|
1401
|
-
if (entry && typeof entry === "object" && "output" in entry && entry.output !== undefined) {
|
|
1402
|
-
return true;
|
|
1403
|
-
}
|
|
1404
|
-
if (kind === "invokeChildWorkflow" && timeline[invokeChildWorkflowTimelineKey(stepId)]) {
|
|
1405
|
-
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);
|
|
1406
1410
|
}
|
|
1407
|
-
return false;
|
|
1408
|
-
}
|
|
1409
|
-
function otelPlugin(options = {}) {
|
|
1410
|
-
const tracer = options.tracer ?? trace.getTracer("pg-workflows");
|
|
1411
|
-
const prefix = options.spanNamePrefix ?? DEFAULT_PREFIX;
|
|
1412
|
-
const extraAttrs = options.attributes;
|
|
1413
|
-
return {
|
|
1414
|
-
name: "opentelemetry",
|
|
1415
|
-
methods: (step, context) => {
|
|
1416
|
-
const wrapVoidish = (kind, base) => {
|
|
1417
|
-
return async (stepId, ...args) => {
|
|
1418
|
-
if (isCachedHit(context.timeline, stepId, kind)) {
|
|
1419
|
-
return base(stepId, ...args);
|
|
1420
|
-
}
|
|
1421
|
-
const capturedCtx = otelContext.active();
|
|
1422
|
-
const startTime = new Date;
|
|
1423
|
-
let result;
|
|
1424
|
-
let originalErr;
|
|
1425
|
-
let thrownError;
|
|
1426
|
-
try {
|
|
1427
|
-
result = await base(stepId, ...args);
|
|
1428
|
-
} catch (err) {
|
|
1429
|
-
originalErr = err;
|
|
1430
|
-
thrownError = err instanceof Error ? err : new Error(String(err));
|
|
1431
|
-
}
|
|
1432
|
-
const span = tracer.startSpan(`${prefix}.step.${kind}`, {
|
|
1433
|
-
startTime,
|
|
1434
|
-
attributes: { "step.id": stepId, "step.type": kind }
|
|
1435
|
-
}, capturedCtx);
|
|
1436
|
-
if (thrownError) {
|
|
1437
|
-
span.recordException(thrownError);
|
|
1438
|
-
span.setStatus({ code: SpanStatusCode.ERROR, message: thrownError.message });
|
|
1439
|
-
span.end();
|
|
1440
|
-
throw originalErr;
|
|
1441
|
-
}
|
|
1442
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
1443
|
-
span.end();
|
|
1444
|
-
return result;
|
|
1445
|
-
};
|
|
1446
|
-
};
|
|
1447
|
-
return {
|
|
1448
|
-
run: async (stepId, handler) => {
|
|
1449
|
-
if (isCachedHit(context.timeline, stepId, "run")) {
|
|
1450
|
-
return step.run(stepId, handler);
|
|
1451
|
-
}
|
|
1452
|
-
const capturedCtx = otelContext.active();
|
|
1453
|
-
const startTime = new Date;
|
|
1454
|
-
let result;
|
|
1455
|
-
let originalErr;
|
|
1456
|
-
let thrownError;
|
|
1457
|
-
try {
|
|
1458
|
-
result = await step.run(stepId, handler);
|
|
1459
|
-
} catch (err) {
|
|
1460
|
-
originalErr = err;
|
|
1461
|
-
thrownError = err instanceof Error ? err : new Error(String(err));
|
|
1462
|
-
}
|
|
1463
|
-
if (result === undefined && !thrownError) {
|
|
1464
|
-
return;
|
|
1465
|
-
}
|
|
1466
|
-
const span = tracer.startSpan(`${prefix}.step.run`, {
|
|
1467
|
-
startTime,
|
|
1468
|
-
attributes: { "step.id": stepId, "step.type": "run" }
|
|
1469
|
-
}, capturedCtx);
|
|
1470
|
-
if (thrownError) {
|
|
1471
|
-
span.recordException(thrownError);
|
|
1472
|
-
span.setStatus({ code: SpanStatusCode.ERROR, message: thrownError.message });
|
|
1473
|
-
span.end();
|
|
1474
|
-
throw originalErr;
|
|
1475
|
-
}
|
|
1476
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
1477
|
-
span.end();
|
|
1478
|
-
return result;
|
|
1479
|
-
},
|
|
1480
|
-
waitFor: wrapVoidish("waitFor", step.waitFor),
|
|
1481
|
-
delay: wrapVoidish("delay", step.delay),
|
|
1482
|
-
sleep: wrapVoidish("delay", step.delay),
|
|
1483
|
-
waitUntil: wrapVoidish("waitUntil", step.waitUntil),
|
|
1484
|
-
pause: wrapVoidish("pause", step.pause),
|
|
1485
|
-
poll: async (stepId, conditionFn, pollOptions) => {
|
|
1486
|
-
const capturedCtx = otelContext.active();
|
|
1487
|
-
const startTime = new Date;
|
|
1488
|
-
let result;
|
|
1489
|
-
let originalErr;
|
|
1490
|
-
let thrownError;
|
|
1491
|
-
try {
|
|
1492
|
-
result = await step.poll(stepId, conditionFn, pollOptions);
|
|
1493
|
-
} catch (err) {
|
|
1494
|
-
originalErr = err;
|
|
1495
|
-
thrownError = err instanceof Error ? err : new Error(String(err));
|
|
1496
|
-
}
|
|
1497
|
-
const span = tracer.startSpan(`${prefix}.step.poll`, {
|
|
1498
|
-
startTime,
|
|
1499
|
-
attributes: { "step.id": stepId, "step.type": "poll" }
|
|
1500
|
-
}, capturedCtx);
|
|
1501
|
-
if (thrownError) {
|
|
1502
|
-
span.recordException(thrownError);
|
|
1503
|
-
span.setStatus({ code: SpanStatusCode.ERROR, message: thrownError.message });
|
|
1504
|
-
span.end();
|
|
1505
|
-
throw originalErr;
|
|
1506
|
-
}
|
|
1507
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
1508
|
-
span.end();
|
|
1509
|
-
return result;
|
|
1510
|
-
},
|
|
1511
|
-
invokeChildWorkflow: async (stepId, refOrParams, inputArg, optionsArg) => {
|
|
1512
|
-
if (isCachedHit(context.timeline, stepId, "invokeChildWorkflow")) {
|
|
1513
|
-
return step.invokeChildWorkflow(stepId, refOrParams, inputArg, optionsArg);
|
|
1514
|
-
}
|
|
1515
|
-
const capturedCtx = otelContext.active();
|
|
1516
|
-
const startTime = new Date;
|
|
1517
|
-
let result;
|
|
1518
|
-
let originalErr;
|
|
1519
|
-
let thrownError;
|
|
1520
|
-
try {
|
|
1521
|
-
result = await step.invokeChildWorkflow(stepId, refOrParams, inputArg, optionsArg);
|
|
1522
|
-
} catch (err) {
|
|
1523
|
-
originalErr = err;
|
|
1524
|
-
thrownError = err instanceof Error ? err : new Error(String(err));
|
|
1525
|
-
}
|
|
1526
|
-
const span = tracer.startSpan(`${prefix}.step.invokeChildWorkflow`, {
|
|
1527
|
-
startTime,
|
|
1528
|
-
attributes: { "step.id": stepId, "step.type": "invokeChildWorkflow" }
|
|
1529
|
-
}, capturedCtx);
|
|
1530
|
-
if (thrownError) {
|
|
1531
|
-
span.recordException(thrownError);
|
|
1532
|
-
span.setStatus({ code: SpanStatusCode.ERROR, message: thrownError.message });
|
|
1533
|
-
span.end();
|
|
1534
|
-
throw originalErr;
|
|
1535
|
-
}
|
|
1536
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
1537
|
-
span.end();
|
|
1538
|
-
return result;
|
|
1539
|
-
}
|
|
1540
|
-
};
|
|
1541
|
-
},
|
|
1542
|
-
wrap: (context, next) => tracer.startActiveSpan(`${prefix}.workflow.run`, {
|
|
1543
|
-
attributes: {
|
|
1544
|
-
"workflow.id": context.workflowId,
|
|
1545
|
-
"workflow.run_id": context.runId,
|
|
1546
|
-
"workflow.attempt": context.attempt,
|
|
1547
|
-
...context.resourceId ? { "workflow.resource_id": context.resourceId } : {},
|
|
1548
|
-
...extraAttrs ? extraAttrs(context) : {}
|
|
1549
|
-
}
|
|
1550
|
-
}, async (span) => {
|
|
1551
|
-
try {
|
|
1552
|
-
const result = await next();
|
|
1553
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
1554
|
-
return result;
|
|
1555
|
-
} catch (err) {
|
|
1556
|
-
const error = err instanceof Error ? err : new Error(String(err));
|
|
1557
|
-
span.recordException(error);
|
|
1558
|
-
span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
|
|
1559
|
-
throw err;
|
|
1560
|
-
} finally {
|
|
1561
|
-
span.end();
|
|
1562
|
-
}
|
|
1563
|
-
})
|
|
1564
|
-
};
|
|
1565
1411
|
}
|
|
1566
1412
|
export {
|
|
1567
1413
|
workflow,
|
|
1568
|
-
|
|
1414
|
+
isStepCached,
|
|
1569
1415
|
createWorkflowRef,
|
|
1570
1416
|
WorkflowStatus,
|
|
1571
1417
|
WorkflowRunNotFoundError,
|
|
1418
|
+
WorkflowRunInProgressError,
|
|
1572
1419
|
WorkflowEngineError,
|
|
1573
1420
|
WorkflowEngine,
|
|
1574
1421
|
WorkflowClient
|
|
1575
1422
|
};
|
|
1576
1423
|
|
|
1577
|
-
//# debugId=
|
|
1424
|
+
//# debugId=5FDB649CAAD8594E64756E2164756E21
|
|
1578
1425
|
//# sourceMappingURL=index.js.map
|