pg-workflows 0.11.0 → 0.12.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/index.js CHANGED
@@ -732,21 +732,32 @@ class WorkflowEngine {
732
732
  };
733
733
  let step = { ...baseStep };
734
734
  const plugins = workflow2.plugins ?? [];
735
- for (const plugin of plugins) {
736
- const extra = plugin.methods(step);
737
- step = { ...step, ...extra };
738
- }
739
735
  const context = {
740
736
  input: run.input,
741
737
  workflowId: run.workflowId,
742
738
  runId: run.id,
739
+ resourceId: run.resourceId ?? undefined,
740
+ attempt: run.retryCount,
743
741
  get timeline() {
744
742
  return run?.timeline ?? {};
745
743
  },
746
744
  logger: this.logger,
747
745
  step
748
746
  };
749
- const result = await workflow2.handler(context);
747
+ for (const plugin of plugins) {
748
+ const extra = plugin.methods(step, context);
749
+ step = { ...step, ...extra };
750
+ context.step = step;
751
+ }
752
+ let next = () => workflow2.handler(context);
753
+ for (const plugin of [...plugins].reverse()) {
754
+ if (plugin.wrap) {
755
+ const inner = next;
756
+ const wrap = plugin.wrap;
757
+ next = () => wrap(context, inner);
758
+ }
759
+ }
760
+ const result = await next();
750
761
  run = await this.getRun({ runId, resourceId: scopedResourceId });
751
762
  const isLastParsedStep = run.currentStepId === workflow2.steps[workflow2.steps.length - 1]?.id;
752
763
  const hasPluginSteps = (workflow2.plugins?.length ?? 0) > 0;
@@ -1279,8 +1290,183 @@ ${error.stack}` : String(error)
1279
1290
  }, this.db);
1280
1291
  }
1281
1292
  }
1293
+ // src/plugins/otel.ts
1294
+ import {
1295
+ context as otelContext,
1296
+ SpanStatusCode,
1297
+ trace
1298
+ } from "@opentelemetry/api";
1299
+ var DEFAULT_PREFIX = "pg_workflows";
1300
+ function isCachedHit(timeline, stepId, kind) {
1301
+ const entry = timeline[stepId];
1302
+ if (entry && typeof entry === "object" && "output" in entry && entry.output !== undefined) {
1303
+ return true;
1304
+ }
1305
+ if (kind === "invokeChildWorkflow" && timeline[invokeChildWorkflowTimelineKey(stepId)]) {
1306
+ return true;
1307
+ }
1308
+ return false;
1309
+ }
1310
+ function otelPlugin(options = {}) {
1311
+ const tracer = options.tracer ?? trace.getTracer("pg-workflows");
1312
+ const prefix = options.spanNamePrefix ?? DEFAULT_PREFIX;
1313
+ const extraAttrs = options.attributes;
1314
+ return {
1315
+ name: "opentelemetry",
1316
+ methods: (step, context) => {
1317
+ const wrapVoidish = (kind, base) => {
1318
+ return async (stepId, ...args) => {
1319
+ if (isCachedHit(context.timeline, stepId, kind)) {
1320
+ return base(stepId, ...args);
1321
+ }
1322
+ const capturedCtx = otelContext.active();
1323
+ const startTime = new Date;
1324
+ let result;
1325
+ let originalErr;
1326
+ let thrownError;
1327
+ try {
1328
+ result = await base(stepId, ...args);
1329
+ } catch (err) {
1330
+ originalErr = err;
1331
+ thrownError = err instanceof Error ? err : new Error(String(err));
1332
+ }
1333
+ const span = tracer.startSpan(`${prefix}.step.${kind}`, {
1334
+ startTime,
1335
+ attributes: { "step.id": stepId, "step.type": kind }
1336
+ }, capturedCtx);
1337
+ if (thrownError) {
1338
+ span.recordException(thrownError);
1339
+ span.setStatus({ code: SpanStatusCode.ERROR, message: thrownError.message });
1340
+ span.end();
1341
+ throw originalErr;
1342
+ }
1343
+ span.setStatus({ code: SpanStatusCode.OK });
1344
+ span.end();
1345
+ return result;
1346
+ };
1347
+ };
1348
+ return {
1349
+ run: async (stepId, handler) => {
1350
+ if (isCachedHit(context.timeline, stepId, "run")) {
1351
+ return step.run(stepId, handler);
1352
+ }
1353
+ const capturedCtx = otelContext.active();
1354
+ const startTime = new Date;
1355
+ let result;
1356
+ let originalErr;
1357
+ let thrownError;
1358
+ try {
1359
+ result = await step.run(stepId, handler);
1360
+ } catch (err) {
1361
+ originalErr = err;
1362
+ thrownError = err instanceof Error ? err : new Error(String(err));
1363
+ }
1364
+ if (result === undefined && !thrownError) {
1365
+ return;
1366
+ }
1367
+ const span = tracer.startSpan(`${prefix}.step.run`, {
1368
+ startTime,
1369
+ attributes: { "step.id": stepId, "step.type": "run" }
1370
+ }, capturedCtx);
1371
+ if (thrownError) {
1372
+ span.recordException(thrownError);
1373
+ span.setStatus({ code: SpanStatusCode.ERROR, message: thrownError.message });
1374
+ span.end();
1375
+ throw originalErr;
1376
+ }
1377
+ span.setStatus({ code: SpanStatusCode.OK });
1378
+ span.end();
1379
+ return result;
1380
+ },
1381
+ waitFor: wrapVoidish("waitFor", step.waitFor),
1382
+ delay: wrapVoidish("delay", step.delay),
1383
+ sleep: wrapVoidish("delay", step.delay),
1384
+ waitUntil: wrapVoidish("waitUntil", step.waitUntil),
1385
+ pause: wrapVoidish("pause", step.pause),
1386
+ poll: async (stepId, conditionFn, pollOptions) => {
1387
+ const capturedCtx = otelContext.active();
1388
+ const startTime = new Date;
1389
+ let result;
1390
+ let originalErr;
1391
+ let thrownError;
1392
+ try {
1393
+ result = await step.poll(stepId, conditionFn, pollOptions);
1394
+ } catch (err) {
1395
+ originalErr = err;
1396
+ thrownError = err instanceof Error ? err : new Error(String(err));
1397
+ }
1398
+ const span = tracer.startSpan(`${prefix}.step.poll`, {
1399
+ startTime,
1400
+ attributes: { "step.id": stepId, "step.type": "poll" }
1401
+ }, capturedCtx);
1402
+ if (thrownError) {
1403
+ span.recordException(thrownError);
1404
+ span.setStatus({ code: SpanStatusCode.ERROR, message: thrownError.message });
1405
+ span.end();
1406
+ throw originalErr;
1407
+ }
1408
+ span.setStatus({ code: SpanStatusCode.OK });
1409
+ span.end();
1410
+ return result;
1411
+ },
1412
+ invokeChildWorkflow: async (stepId, refOrParams, inputArg, optionsArg) => {
1413
+ if (isCachedHit(context.timeline, stepId, "invokeChildWorkflow")) {
1414
+ return step.invokeChildWorkflow(stepId, refOrParams, inputArg, optionsArg);
1415
+ }
1416
+ const capturedCtx = otelContext.active();
1417
+ const startTime = new Date;
1418
+ let result;
1419
+ let originalErr;
1420
+ let thrownError;
1421
+ try {
1422
+ result = await step.invokeChildWorkflow(stepId, refOrParams, inputArg, optionsArg);
1423
+ } catch (err) {
1424
+ originalErr = err;
1425
+ thrownError = err instanceof Error ? err : new Error(String(err));
1426
+ }
1427
+ const span = tracer.startSpan(`${prefix}.step.invokeChildWorkflow`, {
1428
+ startTime,
1429
+ attributes: { "step.id": stepId, "step.type": "invokeChildWorkflow" }
1430
+ }, capturedCtx);
1431
+ if (thrownError) {
1432
+ span.recordException(thrownError);
1433
+ span.setStatus({ code: SpanStatusCode.ERROR, message: thrownError.message });
1434
+ span.end();
1435
+ throw originalErr;
1436
+ }
1437
+ span.setStatus({ code: SpanStatusCode.OK });
1438
+ span.end();
1439
+ return result;
1440
+ }
1441
+ };
1442
+ },
1443
+ wrap: (context, next) => tracer.startActiveSpan(`${prefix}.workflow.run`, {
1444
+ attributes: {
1445
+ "workflow.id": context.workflowId,
1446
+ "workflow.run_id": context.runId,
1447
+ "workflow.attempt": context.attempt,
1448
+ ...context.resourceId ? { "workflow.resource_id": context.resourceId } : {},
1449
+ ...extraAttrs ? extraAttrs(context) : {}
1450
+ }
1451
+ }, async (span) => {
1452
+ try {
1453
+ const result = await next();
1454
+ span.setStatus({ code: SpanStatusCode.OK });
1455
+ return result;
1456
+ } catch (err) {
1457
+ const error = err instanceof Error ? err : new Error(String(err));
1458
+ span.recordException(error);
1459
+ span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
1460
+ throw err;
1461
+ } finally {
1462
+ span.end();
1463
+ }
1464
+ })
1465
+ };
1466
+ }
1282
1467
  export {
1283
1468
  workflow,
1469
+ otelPlugin,
1284
1470
  createWorkflowRef,
1285
1471
  WorkflowStatus,
1286
1472
  WorkflowRunNotFoundError,
@@ -1289,5 +1475,5 @@ export {
1289
1475
  WorkflowClient
1290
1476
  };
1291
1477
 
1292
- //# debugId=F9D6596295A7020B64756E2164756E21
1478
+ //# debugId=3131CBB2B482181264756E2164756E21
1293
1479
  //# sourceMappingURL=index.js.map