@falcondev-oss/workflow 0.9.0 → 0.9.1

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.d.mts CHANGED
@@ -13,6 +13,7 @@ type WorkflowLogger = {
13
13
  success?: (...data: any[]) => void;
14
14
  error?: (...data: any[]) => void;
15
15
  debug?: (...data: any[]) => void;
16
+ warn?: (...data: any[]) => void;
16
17
  };
17
18
  declare const Settings: {
18
19
  defaultConnection: (() => Promise<IORedis> | IORedis) | undefined;
@@ -45,11 +46,16 @@ declare class WorkflowStep {
45
46
  private workflowJobId;
46
47
  private stepNamePrefix;
47
48
  private updateStepDataMutex;
49
+ private meta;
48
50
  constructor(opts: {
49
51
  queue: WorkflowQueueInternal<unknown>;
50
52
  workflowJobId: string;
51
53
  workflowId: string;
52
54
  stepNamePrefix?: string;
55
+ meta: {
56
+ stepPromises: Set<Promise<any>>;
57
+ isCanceled: boolean;
58
+ };
53
59
  });
54
60
  private addNamePrefix;
55
61
  do<R>(stepName: string, run: (ctx: {
package/dist/index.mjs CHANGED
@@ -9628,11 +9628,13 @@ var WorkflowStep = class WorkflowStep {
9628
9628
  workflowJobId;
9629
9629
  stepNamePrefix;
9630
9630
  updateStepDataMutex = new Mutex();
9631
+ meta;
9631
9632
  constructor(opts) {
9632
9633
  this.queue = opts.queue;
9633
9634
  this.workflowJobId = opts.workflowJobId;
9634
9635
  this.workflowId = opts.workflowId;
9635
9636
  this.stepNamePrefix = opts.stepNamePrefix ? `${opts.stepNamePrefix}|` : "";
9637
+ this.meta = opts.meta;
9636
9638
  }
9637
9639
  addNamePrefix(name) {
9638
9640
  return `${this.stepNamePrefix}${name}`;
@@ -9650,7 +9652,7 @@ var WorkflowStep = class WorkflowStep {
9650
9652
  attempt: initialAttempt
9651
9653
  });
9652
9654
  Settings.logger?.debug?.(`[${this.workflowId}/${this.workflowJobId}] Running step '${name}' (attempt ${initialAttempt + 1})`);
9653
- return pRetry(async (attempt) => {
9655
+ const promise = pRetry(async (attempt) => {
9654
9656
  const result = await runWithTracing(`workflow-worker/${this.workflowId}/step/${name}`, { attributes: {
9655
9657
  "workflow.id": this.workflowId,
9656
9658
  "workflow.job_id": this.workflowJobId,
@@ -9661,7 +9663,8 @@ var WorkflowStep = class WorkflowStep {
9661
9663
  queue: this.queue,
9662
9664
  workflowId: this.workflowId,
9663
9665
  workflowJobId: this.workflowJobId,
9664
- stepNamePrefix: name
9666
+ stepNamePrefix: name,
9667
+ meta: this.meta
9665
9668
  }),
9666
9669
  span
9667
9670
  }));
@@ -9682,8 +9685,14 @@ var WorkflowStep = class WorkflowStep {
9682
9685
  attempt: initialAttempt + ctx.attemptNumber
9683
9686
  });
9684
9687
  return options?.retry?.onFailedAttempt?.(ctx);
9688
+ },
9689
+ shouldRetry: async (context$1) => {
9690
+ if (this.meta.isCanceled) return false;
9691
+ return options?.retry?.shouldRetry?.(context$1) ?? true;
9685
9692
  }
9686
9693
  });
9694
+ this.meta.stepPromises.add(promise);
9695
+ return promise.finally(() => this.meta.stepPromises.delete(promise));
9687
9696
  }
9688
9697
  async wait(stepName, durationMs) {
9689
9698
  const name = this.addNamePrefix(stepName);
@@ -9758,19 +9767,33 @@ var Workflow = class {
9758
9767
  },
9759
9768
  kind: SpanKind.CONSUMER
9760
9769
  }, async (span) => {
9770
+ const stepMeta = {
9771
+ stepPromises: /* @__PURE__ */ new Set(),
9772
+ isCanceled: false
9773
+ };
9761
9774
  const start = performance.now();
9762
- const result = await this.opts.run({
9763
- input: parsedData?.value,
9764
- step: new WorkflowStep({
9765
- queue,
9766
- workflowJobId: jobId,
9767
- workflowId: this.opts.id
9768
- }),
9769
- span
9770
- });
9771
- const end = performance.now();
9772
- Settings.logger?.success?.(`[${this.opts.id}] Completed job ${job.id} in ${(end - start).toFixed(2)} ms`);
9773
- return serialize$1(result);
9775
+ try {
9776
+ const result = await this.opts.run({
9777
+ input: parsedData?.value,
9778
+ step: new WorkflowStep({
9779
+ queue,
9780
+ workflowJobId: jobId,
9781
+ workflowId: this.opts.id,
9782
+ meta: stepMeta
9783
+ }),
9784
+ span
9785
+ });
9786
+ const end = performance.now();
9787
+ Settings.logger?.success?.(`[${this.opts.id}] Completed job ${job.id} in ${(end - start).toFixed(2)} ms`);
9788
+ return serialize$1(result);
9789
+ } catch (err) {
9790
+ stepMeta.isCanceled = true;
9791
+ if (stepMeta.stepPromises.size > 0) {
9792
+ Settings.logger?.warn?.(`[${this.opts.id}] Job failed but there are still ${stepMeta.stepPromises.size} running step(s), waiting for them to finish. Be careful when using 'Promise.all([step0, step1, ...])', as running steps are not canceled when one of them fails.`);
9793
+ await Promise.allSettled(stepMeta.stepPromises);
9794
+ }
9795
+ throw err;
9796
+ }
9774
9797
  }, propagation.extract(ROOT_CONTEXT, deserializedData.tracingHeaders));
9775
9798
  },
9776
9799
  queue,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@falcondev-oss/workflow",
3
3
  "type": "module",
4
- "version": "0.9.0",
4
+ "version": "0.9.1",
5
5
  "description": "Simple type-safe queue worker with durable execution using Redis.",
6
6
  "license": "MIT",
7
7
  "repository": "github:falcondev-oss/workflow",