@falcondev-oss/workflow 0.8.9 → 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;
@@ -22,7 +23,9 @@ declare const Settings: {
22
23
  prefix: string;
23
24
  } | undefined;
24
25
  };
25
- declare function createRedis(opts: RedisOptions): Promise<IORedis>;
26
+ declare function createRedis(opts: RedisOptions & {
27
+ url?: string;
28
+ }): Promise<IORedis>;
26
29
  //#endregion
27
30
  //#region src/serializer.d.ts
28
31
  type Serialized<T> = Tagged<SuperJSONResult, 'data', T>;
@@ -43,11 +46,16 @@ declare class WorkflowStep {
43
46
  private workflowJobId;
44
47
  private stepNamePrefix;
45
48
  private updateStepDataMutex;
49
+ private meta;
46
50
  constructor(opts: {
47
51
  queue: WorkflowQueueInternal<unknown>;
48
52
  workflowJobId: string;
49
53
  workflowId: string;
50
54
  stepNamePrefix?: string;
55
+ meta: {
56
+ stepPromises: Set<Promise<any>>;
57
+ isCanceled: boolean;
58
+ };
51
59
  });
52
60
  private addNamePrefix;
53
61
  do<R>(stepName: string, run: (ctx: {
package/dist/index.mjs CHANGED
@@ -57,10 +57,11 @@ const defaultRedisConnection = createSingletonPromise(async () => {
57
57
  return redis;
58
58
  });
59
59
  async function createRedis(opts) {
60
- const redis = new IORedis({
60
+ const redisOpts = {
61
61
  ...defaultRedisOptions,
62
62
  ...opts
63
- });
63
+ };
64
+ const redis = opts.url ? new IORedis(opts.url, redisOpts) : new IORedis(redisOpts);
64
65
  await redis.connect();
65
66
  return redis;
66
67
  }
@@ -9627,11 +9628,13 @@ var WorkflowStep = class WorkflowStep {
9627
9628
  workflowJobId;
9628
9629
  stepNamePrefix;
9629
9630
  updateStepDataMutex = new Mutex();
9631
+ meta;
9630
9632
  constructor(opts) {
9631
9633
  this.queue = opts.queue;
9632
9634
  this.workflowJobId = opts.workflowJobId;
9633
9635
  this.workflowId = opts.workflowId;
9634
9636
  this.stepNamePrefix = opts.stepNamePrefix ? `${opts.stepNamePrefix}|` : "";
9637
+ this.meta = opts.meta;
9635
9638
  }
9636
9639
  addNamePrefix(name) {
9637
9640
  return `${this.stepNamePrefix}${name}`;
@@ -9649,7 +9652,7 @@ var WorkflowStep = class WorkflowStep {
9649
9652
  attempt: initialAttempt
9650
9653
  });
9651
9654
  Settings.logger?.debug?.(`[${this.workflowId}/${this.workflowJobId}] Running step '${name}' (attempt ${initialAttempt + 1})`);
9652
- return pRetry(async (attempt) => {
9655
+ const promise = pRetry(async (attempt) => {
9653
9656
  const result = await runWithTracing(`workflow-worker/${this.workflowId}/step/${name}`, { attributes: {
9654
9657
  "workflow.id": this.workflowId,
9655
9658
  "workflow.job_id": this.workflowJobId,
@@ -9660,7 +9663,8 @@ var WorkflowStep = class WorkflowStep {
9660
9663
  queue: this.queue,
9661
9664
  workflowId: this.workflowId,
9662
9665
  workflowJobId: this.workflowJobId,
9663
- stepNamePrefix: name
9666
+ stepNamePrefix: name,
9667
+ meta: this.meta
9664
9668
  }),
9665
9669
  span
9666
9670
  }));
@@ -9681,8 +9685,14 @@ var WorkflowStep = class WorkflowStep {
9681
9685
  attempt: initialAttempt + ctx.attemptNumber
9682
9686
  });
9683
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;
9684
9692
  }
9685
9693
  });
9694
+ this.meta.stepPromises.add(promise);
9695
+ return promise.finally(() => this.meta.stepPromises.delete(promise));
9686
9696
  }
9687
9697
  async wait(stepName, durationMs) {
9688
9698
  const name = this.addNamePrefix(stepName);
@@ -9757,19 +9767,33 @@ var Workflow = class {
9757
9767
  },
9758
9768
  kind: SpanKind.CONSUMER
9759
9769
  }, async (span) => {
9770
+ const stepMeta = {
9771
+ stepPromises: /* @__PURE__ */ new Set(),
9772
+ isCanceled: false
9773
+ };
9760
9774
  const start = performance.now();
9761
- const result = await this.opts.run({
9762
- input: parsedData?.value,
9763
- step: new WorkflowStep({
9764
- queue,
9765
- workflowJobId: jobId,
9766
- workflowId: this.opts.id
9767
- }),
9768
- span
9769
- });
9770
- const end = performance.now();
9771
- Settings.logger?.success?.(`[${this.opts.id}] Completed job ${job.id} in ${(end - start).toFixed(2)} ms`);
9772
- 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
+ }
9773
9797
  }, propagation.extract(ROOT_CONTEXT, deserializedData.tracingHeaders));
9774
9798
  },
9775
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.8.9",
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",