duron 0.3.0-beta.8 → 0.3.0-beta.9

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.
@@ -1 +1 @@
1
- {"version":3,"file":"action-job.d.ts","sourceRoot":"","sources":["../src/action-job.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAElC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AAGpD,OAAO,KAAK,EAAQ,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAGpE,MAAM,WAAW,gBAAgB,CAAC,OAAO,SAAS,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACrE,GAAG,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,GAAG,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAA;IACxF,MAAM,EAAE,OAAO,CAAA;IACf,QAAQ,EAAE,OAAO,CAAA;IACjB,SAAS,EAAE,gBAAgB,CAAA;IAC3B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAClC,MAAM,EAAE,MAAM,CAAA;CACf;AAQD,qBAAa,SAAS,CAAC,OAAO,SAAS,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;;gBAuB9C,OAAO,EAAE,gBAAgB,CAAC,OAAO,CAAC;IAsCxC,OAAO;IA2Hb,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ5B,MAAM;CAmBP"}
1
+ {"version":3,"file":"action-job.d.ts","sourceRoot":"","sources":["../src/action-job.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAElC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AAGpD,OAAO,KAAK,EAAQ,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAGpE,MAAM,WAAW,gBAAgB,CAAC,OAAO,SAAS,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACrE,GAAG,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,GAAG,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAA;IACxF,MAAM,EAAE,OAAO,CAAA;IACf,QAAQ,EAAE,OAAO,CAAA;IACjB,SAAS,EAAE,gBAAgB,CAAA;IAC3B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAClC,MAAM,EAAE,MAAM,CAAA;CACf;AAQD,qBAAa,SAAS,CAAC,OAAO,SAAS,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;;gBAuB9C,OAAO,EAAE,gBAAgB,CAAC,OAAO,CAAC;IAsCxC,OAAO;IAkIb,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ5B,MAAM;CAmBP"}
@@ -1,4 +1,4 @@
1
- import { ActionCancelError, ActionTimeoutError, isCancelError, StepTimeoutError, serializeError } from './errors.js';
1
+ import { ActionCancelError, ActionTimeoutError, isCancelError, isTimeoutError, serializeError } from './errors.js';
2
2
  import { StepManager } from './step-manager.js';
3
3
  import waitForAbort from './utils/wait-for-abort.js';
4
4
  export class ActionJob {
@@ -84,6 +84,10 @@ export class ActionJob {
84
84
  return result;
85
85
  }
86
86
  catch (error) {
87
+ if (!this.#abortController.signal.aborted) {
88
+ this.#abortController.abort(error);
89
+ }
90
+ await this.#stepManager.drain();
87
91
  if (isCancelError(error) ||
88
92
  (error instanceof Error && error.name === 'AbortError' && isCancelError(error.cause))) {
89
93
  this.#logger.warn({ jobId: this.#job.id, actionName: this.#action.name }, '[ActionJob] Job cancelled');
@@ -93,11 +97,9 @@ export class ActionJob {
93
97
  }
94
98
  return;
95
99
  }
96
- const message = error instanceof ActionTimeoutError
100
+ const message = isTimeoutError(error)
97
101
  ? '[ActionJob] Job timed out'
98
- : error instanceof StepTimeoutError
99
- ? '[ActionJob] Step timed out'
100
- : '[ActionJob] Job failed';
102
+ : '[ActionJob] Job failed';
101
103
  this.#logger.error({ jobId: this.#job.id, actionName: this.#action.name }, message);
102
104
  await this.#database.failJob({ jobId: this.#job.id, error: serializeError(error) });
103
105
  if (this.#jobSpan) {
package/dist/errors.d.ts CHANGED
@@ -1,30 +1,53 @@
1
+ export declare const ERROR_CODES: {
2
+ readonly DURON_ERROR: "DURON_ERROR";
3
+ readonly STEP_ALREADY_EXECUTED: "STEP_ALREADY_EXECUTED";
4
+ readonly NON_RETRIABLE: "NON_RETRIABLE";
5
+ readonly ACTION_TIMEOUT: "ACTION_TIMEOUT";
6
+ readonly STEP_TIMEOUT: "STEP_TIMEOUT";
7
+ readonly ACTION_CANCEL: "ACTION_CANCEL";
8
+ readonly UNHANDLED_CHILD_STEPS: "UNHANDLED_CHILD_STEPS";
9
+ };
10
+ export type ErrorCode = (typeof ERROR_CODES)[keyof typeof ERROR_CODES];
1
11
  export declare abstract class DuronError extends Error {
12
+ readonly code: ErrorCode;
13
+ readonly nonRetriable: boolean;
2
14
  readonly cause?: unknown;
3
15
  constructor(message: string, options?: {
4
16
  cause?: unknown;
5
17
  });
6
18
  }
7
19
  export declare class StepAlreadyExecutedError extends DuronError {
20
+ readonly code: "STEP_ALREADY_EXECUTED";
21
+ readonly nonRetriable = true;
8
22
  constructor(stepName: string, jobId: string, actionName: string);
9
23
  }
10
24
  export declare class NonRetriableError extends DuronError {
25
+ readonly code: ErrorCode;
26
+ readonly nonRetriable = true;
11
27
  }
12
28
  export declare class ActionTimeoutError extends DuronError {
29
+ readonly code: "ACTION_TIMEOUT";
30
+ readonly nonRetriable = true;
13
31
  constructor(actionName: string, timeoutMs: number, options?: {
14
32
  cause?: unknown;
15
33
  });
16
34
  }
17
35
  export declare class StepTimeoutError extends DuronError {
36
+ readonly code: "STEP_TIMEOUT";
37
+ readonly nonRetriable = false;
18
38
  constructor(stepName: string, jobId: string, timeoutMs: number, options?: {
19
39
  cause?: unknown;
20
40
  });
21
41
  }
22
42
  export declare class ActionCancelError extends DuronError {
43
+ readonly code: "ACTION_CANCEL";
44
+ readonly nonRetriable = true;
23
45
  constructor(actionName: string, jobId: string, options?: {
24
46
  cause?: unknown;
25
47
  });
26
48
  }
27
49
  export declare class UnhandledChildStepsError extends NonRetriableError {
50
+ readonly code: "UNHANDLED_CHILD_STEPS";
28
51
  readonly stepName: string;
29
52
  readonly pendingCount: number;
30
53
  constructor(stepName: string, pendingCount: number);
@@ -37,13 +60,10 @@ export declare function isCancelError(error: unknown): error is ActionCancelErro
37
60
  export type SerializableError = {
38
61
  name: string;
39
62
  message: string;
63
+ code?: ErrorCode;
64
+ nonRetriable?: boolean;
40
65
  cause?: unknown;
41
66
  stack?: string;
42
67
  };
43
- export declare function serializeError(error: unknown): {
44
- name: string;
45
- message: string;
46
- cause?: unknown;
47
- stack?: string;
48
- };
68
+ export declare function serializeError(error: unknown): SerializableError;
49
69
  //# sourceMappingURL=errors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAIA,8BAAsB,UAAW,SAAQ,KAAK;IAM5C,SAAyB,KAAK,CAAC,EAAE,OAAO,CAAA;gBAGtC,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAMR,KAAK,CAAC,EAAE,OAAO,CAAA;KAChB;CAWJ;AAKD,qBAAa,wBAAyB,SAAQ,UAAU;gBAQ1C,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;CAGhE;AAQD,qBAAa,iBAAkB,SAAQ,UAAU;CAEhD;AAKD,qBAAa,kBAAmB,SAAQ,UAAU;gBAS9C,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE;QACR,KAAK,CAAC,EAAE,OAAO,CAAA;KAChB;CAIJ;AAKD,qBAAa,gBAAiB,SAAQ,UAAU;gBAU5C,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE;QACR,KAAK,CAAC,EAAE,OAAO,CAAA;KAChB;CAIJ;AAKD,qBAAa,iBAAkB,SAAQ,UAAU;gBAS7C,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE;QACR,KAAK,CAAC,EAAE,OAAO,CAAA;KAChB;CAIJ;AAQD,qBAAa,wBAAyB,SAAQ,iBAAiB;IAI7D,SAAgB,QAAQ,EAAE,MAAM,CAAA;IAKhC,SAAgB,YAAY,EAAE,MAAM,CAAA;gBAQxB,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM;CAOnD;AAKD,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAEhE;AAKD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,iBAAiB,CAO9E;AAKD,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,wBAAwB,CAE5F;AAKD,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,kBAAkB,GAAG,gBAAgB,CAE7F;AAKD,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,iBAAiB,CAExE;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAMD,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG;IAC9C,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAgCA"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,WAAW;;;;;;;;CAQd,CAAA;AAEV,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,OAAO,WAAW,CAAC,CAAA;AAMtE,8BAAsB,UAAW,SAAQ,KAAK;IAI5C,SAAgB,IAAI,EAAE,SAAS,CAA0B;IAKzD,SAAgB,YAAY,EAAE,OAAO,CAAQ;IAO7C,SAAyB,KAAK,CAAC,EAAE,OAAO,CAAA;gBAGtC,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAMR,KAAK,CAAC,EAAE,OAAO,CAAA;KAChB;CAWJ;AAKD,qBAAa,wBAAyB,SAAQ,UAAU;IACtD,SAAyB,IAAI,0BAAoC;IACjE,SAAyB,YAAY,QAAO;gBAShC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;CAGhE;AAQD,qBAAa,iBAAkB,SAAQ,UAAU;IAC/C,SAAyB,IAAI,EAAE,SAAS,CAA4B;IACpE,SAAyB,YAAY,QAAO;CAC7C;AAKD,qBAAa,kBAAmB,SAAQ,UAAU;IAChD,SAAyB,IAAI,mBAA6B;IAC1D,SAAyB,YAAY,QAAO;gBAU1C,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE;QACR,KAAK,CAAC,EAAE,OAAO,CAAA;KAChB;CAIJ;AAKD,qBAAa,gBAAiB,SAAQ,UAAU;IAC9C,SAAyB,IAAI,iBAA2B;IACxD,SAAyB,YAAY,SAAQ;gBAW3C,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE;QACR,KAAK,CAAC,EAAE,OAAO,CAAA;KAChB;CAIJ;AAKD,qBAAa,iBAAkB,SAAQ,UAAU;IAC/C,SAAyB,IAAI,kBAA4B;IACzD,SAAyB,YAAY,QAAO;gBAU1C,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE;QACR,KAAK,CAAC,EAAE,OAAO,CAAA;KAChB;CAIJ;AAQD,qBAAa,wBAAyB,SAAQ,iBAAiB;IAC7D,SAAyB,IAAI,0BAAoC;IAKjE,SAAgB,QAAQ,EAAE,MAAM,CAAA;IAKhC,SAAgB,YAAY,EAAE,MAAM,CAAA;gBAQxB,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM;CAOnD;AAKD,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAGhE;AAKD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,iBAAiB,CAE9E;AAKD,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,wBAAwB,CAE5F;AAKD,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,kBAAkB,GAAG,gBAAgB,CAG7F;AAKD,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,iBAAiB,CAExE;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAMD,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,iBAAiB,CAuChE"}
package/dist/errors.js CHANGED
@@ -1,4 +1,15 @@
1
+ export const ERROR_CODES = {
2
+ DURON_ERROR: 'DURON_ERROR',
3
+ STEP_ALREADY_EXECUTED: 'STEP_ALREADY_EXECUTED',
4
+ NON_RETRIABLE: 'NON_RETRIABLE',
5
+ ACTION_TIMEOUT: 'ACTION_TIMEOUT',
6
+ STEP_TIMEOUT: 'STEP_TIMEOUT',
7
+ ACTION_CANCEL: 'ACTION_CANCEL',
8
+ UNHANDLED_CHILD_STEPS: 'UNHANDLED_CHILD_STEPS',
9
+ };
1
10
  export class DuronError extends Error {
11
+ code = ERROR_CODES.DURON_ERROR;
12
+ nonRetriable = false;
2
13
  cause;
3
14
  constructor(message, options) {
4
15
  super(message);
@@ -10,28 +21,39 @@ export class DuronError extends Error {
10
21
  }
11
22
  }
12
23
  export class StepAlreadyExecutedError extends DuronError {
24
+ code = ERROR_CODES.STEP_ALREADY_EXECUTED;
25
+ nonRetriable = true;
13
26
  constructor(stepName, jobId, actionName) {
14
27
  super(`Step "${stepName}" has already been executed for job "${jobId}" and action "${actionName}"`);
15
28
  }
16
29
  }
17
30
  export class NonRetriableError extends DuronError {
31
+ code = ERROR_CODES.NON_RETRIABLE;
32
+ nonRetriable = true;
18
33
  }
19
34
  export class ActionTimeoutError extends DuronError {
35
+ code = ERROR_CODES.ACTION_TIMEOUT;
36
+ nonRetriable = true;
20
37
  constructor(actionName, timeoutMs, options) {
21
38
  super(`Action "${actionName}" timed out after ${timeoutMs}ms`, options);
22
39
  }
23
40
  }
24
41
  export class StepTimeoutError extends DuronError {
42
+ code = ERROR_CODES.STEP_TIMEOUT;
43
+ nonRetriable = false;
25
44
  constructor(stepName, jobId, timeoutMs, options) {
26
45
  super(`Step "${stepName}" in job "${jobId}" timed out after ${timeoutMs}ms`, options);
27
46
  }
28
47
  }
29
48
  export class ActionCancelError extends DuronError {
49
+ code = ERROR_CODES.ACTION_CANCEL;
50
+ nonRetriable = true;
30
51
  constructor(actionName, jobId, options) {
31
52
  super(`Action "${actionName}" in job "${jobId}" was cancelled`, options);
32
53
  }
33
54
  }
34
55
  export class UnhandledChildStepsError extends NonRetriableError {
56
+ code = ERROR_CODES.UNHANDLED_CHILD_STEPS;
35
57
  stepName;
36
58
  pendingCount;
37
59
  constructor(stepName, pendingCount) {
@@ -41,36 +63,41 @@ export class UnhandledChildStepsError extends NonRetriableError {
41
63
  }
42
64
  }
43
65
  export function isDuronError(error) {
44
- return error instanceof DuronError;
66
+ const code = error?.code;
67
+ return code !== undefined && Object.values(ERROR_CODES).includes(code);
45
68
  }
46
69
  export function isNonRetriableError(error) {
47
- return (error instanceof NonRetriableError ||
48
- error instanceof ActionCancelError ||
49
- error instanceof ActionTimeoutError ||
50
- error instanceof UnhandledChildStepsError);
70
+ return error?.nonRetriable === true;
51
71
  }
52
72
  export function isUnhandledChildStepsError(error) {
53
- return error instanceof UnhandledChildStepsError;
73
+ return error?.code === ERROR_CODES.UNHANDLED_CHILD_STEPS;
54
74
  }
55
75
  export function isTimeoutError(error) {
56
- return error instanceof ActionTimeoutError || error instanceof StepTimeoutError;
76
+ const code = error?.code;
77
+ return code === ERROR_CODES.ACTION_TIMEOUT || code === ERROR_CODES.STEP_TIMEOUT;
57
78
  }
58
79
  export function isCancelError(error) {
59
- return error instanceof ActionCancelError;
80
+ return error?.code === ERROR_CODES.ACTION_CANCEL;
60
81
  }
61
82
  export function serializeError(error) {
62
- if (error instanceof StepTimeoutError || error instanceof ActionTimeoutError) {
83
+ const code = error?.code;
84
+ const nonRetriable = error?.nonRetriable;
85
+ if (isTimeoutError(error)) {
63
86
  return {
64
87
  name: error.name,
65
88
  message: error.message,
89
+ code,
90
+ nonRetriable,
66
91
  cause: error.cause,
67
92
  stack: undefined,
68
93
  };
69
94
  }
70
- if (error instanceof DuronError) {
95
+ if (isDuronError(error)) {
71
96
  return {
72
97
  name: error.name,
73
98
  message: error.message,
99
+ code,
100
+ nonRetriable,
74
101
  cause: error.cause,
75
102
  stack: error.stack,
76
103
  };
@@ -1 +1 @@
1
- {"version":3,"file":"step-manager.d.ts","sourceRoot":"","sources":["../src/step-manager.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAClC,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAE5B,OAAO,EACL,KAAK,MAAM,EACX,KAAK,oBAAoB,EAGzB,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAEjB,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EAAE,OAAO,EAAgC,MAAM,uBAAuB,CAAA;AAClF,OAAO,EAAoE,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAWlH,OAAO,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,gBAAgB,EAAsB,MAAM,wBAAwB,CAAA;AA2CxG,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,EAAE,EAAE,CAAC,GAAG,EAAE,kBAAkB,KAAK,OAAO,CAAC,GAAG,CAAC,CAAA;IAC7C,OAAO,EAAE,WAAW,CAAA;IACpB,WAAW,EAAE,WAAW,CAAA;IACxB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,QAAQ,EAAE,OAAO,CAAA;CAClB;AAMD,qBAAa,SAAS;;gBAYR,OAAO,EAAE,OAAO;IAoBtB,WAAW,CACf,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,YAAY,GAAE,MAAM,GAAG,IAAW,EAClC,QAAQ,GAAE,OAAe;;;;;;;;;;IAyBrB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC;IAoB7F,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC;CAG3E;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,gBAAgB,CAAA;IAC3B,MAAM,EAAE,MAAM,CAAA;IACd,gBAAgB,EAAE,MAAM,CAAA;CACzB;AAMD,qBAAa,WAAW;;gBAyBV,OAAO,EAAE,kBAAkB;IAqBvC,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAU5B,eAAe,CAAC,OAAO,EAAE,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,EAAE,WAAW,EAAE,WAAW,KAAK,kBAAkB,CAAC,KAAK,CAAC,GAAG,IAAI;IAoBpH,mBAAmB,CAAC,MAAM,SAAS,CAAC,CAAC,SAAS,EAAE,OAAO,SAAS,CAAC,CAAC,SAAS,EAAE,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/G,GAAG,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,EAC9D,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,EAC3C,SAAS,EAAE,UAAU,EACrB,WAAW,EAAE,WAAW,EACxB,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,cAAc,GAC7B,oBAAoB,CAAC,MAAM,EAAE,UAAU,CAAC;IAO3C,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc;IAgClD,IAAI,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC;IAuBlC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAkT7B"}
1
+ {"version":3,"file":"step-manager.d.ts","sourceRoot":"","sources":["../src/step-manager.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAClC,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAE5B,OAAO,EACL,KAAK,MAAM,EACX,KAAK,oBAAoB,EAGzB,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAEjB,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EAAE,OAAO,EAAgC,MAAM,uBAAuB,CAAA;AAClF,OAAO,EAAoE,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAYlH,OAAO,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,gBAAgB,EAAsB,MAAM,wBAAwB,CAAA;AA2CxG,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,EAAE,EAAE,CAAC,GAAG,EAAE,kBAAkB,KAAK,OAAO,CAAC,GAAG,CAAC,CAAA;IAC7C,OAAO,EAAE,WAAW,CAAA;IACpB,WAAW,EAAE,WAAW,CAAA;IACxB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,QAAQ,EAAE,OAAO,CAAA;CAClB;AAMD,qBAAa,SAAS;;gBAYR,OAAO,EAAE,OAAO;IAoBtB,WAAW,CACf,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,YAAY,GAAE,MAAM,GAAG,IAAW,EAClC,QAAQ,GAAE,OAAe;;;;;;;;;;IAyBrB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC;IAoB7F,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC;CAG3E;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,gBAAgB,CAAA;IAC3B,MAAM,EAAE,MAAM,CAAA;IACd,gBAAgB,EAAE,MAAM,CAAA;CACzB;AAMD,qBAAa,WAAW;;gBAyBV,OAAO,EAAE,kBAAkB;IAqBvC,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAU5B,eAAe,CAAC,OAAO,EAAE,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,EAAE,WAAW,EAAE,WAAW,KAAK,kBAAkB,CAAC,KAAK,CAAC,GAAG,IAAI;IAoBpH,mBAAmB,CAAC,MAAM,SAAS,CAAC,CAAC,SAAS,EAAE,OAAO,SAAS,CAAC,CAAC,SAAS,EAAE,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/G,GAAG,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,EAC9D,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,EAC3C,SAAS,EAAE,UAAU,EACrB,WAAW,EAAE,WAAW,EACxB,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,cAAc,GAC7B,oBAAoB,CAAC,MAAM,EAAE,UAAU,CAAC;IAO3C,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc;IAgClD,IAAI,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC;IAuBlC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CA4T7B"}
@@ -1,7 +1,7 @@
1
1
  import fastq from 'fastq';
2
2
  import { StepOptionsSchema, } from './action.js';
3
3
  import { STEP_STATUS_CANCELLED, STEP_STATUS_COMPLETED, STEP_STATUS_FAILED } from './constants.js';
4
- import { ActionCancelError, isCancelError, isNonRetriableError, NonRetriableError, StepAlreadyExecutedError, StepTimeoutError, serializeError, UnhandledChildStepsError, } from './errors.js';
4
+ import { ActionCancelError, isCancelError, isNonRetriableError, isTimeoutError, NonRetriableError, StepAlreadyExecutedError, StepTimeoutError, serializeError, UnhandledChildStepsError, } from './errors.js';
5
5
  const noopTracerSpan = {
6
6
  setAttribute() {
7
7
  },
@@ -298,6 +298,14 @@ export class StepManager {
298
298
  throw new Error(`Failed to delay step "${name}" for job "${this.#jobId}" action "${this.#actionName}"`);
299
299
  }
300
300
  }
301
+ else {
302
+ if (isTimeoutError(error)) {
303
+ ;
304
+ error.nonRetriable = true;
305
+ throw error;
306
+ }
307
+ throw new NonRetriableError(`Failed to execute step="${name}", jobId="${this.#jobId}", action="${this.#actionName}", parentStepId="${parentStepId}"`, { cause: error });
308
+ }
301
309
  },
302
310
  }).catch(async (error) => {
303
311
  if (step) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "duron",
3
- "version": "0.3.0-beta.8",
3
+ "version": "0.3.0-beta.9",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
package/src/action-job.ts CHANGED
@@ -2,7 +2,7 @@ import type { Logger } from 'pino'
2
2
 
3
3
  import type { Action } from './action.js'
4
4
  import type { Adapter } from './adapters/adapter.js'
5
- import { ActionCancelError, ActionTimeoutError, isCancelError, StepTimeoutError, serializeError } from './errors.js'
5
+ import { ActionCancelError, ActionTimeoutError, isCancelError, isTimeoutError, serializeError } from './errors.js'
6
6
  import { StepManager } from './step-manager.js'
7
7
  import type { Span, TelemetryAdapter } from './telemetry/adapter.js'
8
8
  import waitForAbort from './utils/wait-for-abort.js'
@@ -164,6 +164,15 @@ export class ActionJob<TAction extends Action<any, any, any>> {
164
164
 
165
165
  return result
166
166
  } catch (error) {
167
+ // Abort all running steps when an error occurs
168
+ // This ensures cascading failure and stops any steps still running
169
+ if (!this.#abortController.signal.aborted) {
170
+ this.#abortController.abort(error)
171
+ }
172
+
173
+ // Wait for step manager to drain (all steps to settle)
174
+ await this.#stepManager.drain()
175
+
167
176
  if (
168
177
  isCancelError(error) ||
169
178
  (error instanceof Error && error.name === 'AbortError' && isCancelError(error.cause))
@@ -179,11 +188,9 @@ export class ActionJob<TAction extends Action<any, any, any>> {
179
188
  }
180
189
 
181
190
  const message =
182
- error instanceof ActionTimeoutError
191
+ isTimeoutError(error)
183
192
  ? '[ActionJob] Job timed out'
184
- : error instanceof StepTimeoutError
185
- ? '[ActionJob] Step timed out'
186
- : '[ActionJob] Job failed'
193
+ : '[ActionJob] Job failed'
187
194
 
188
195
  this.#logger.error({ jobId: this.#job.id, actionName: this.#action.name }, message)
189
196
  await this.#database.failJob({ jobId: this.#job.id, error: serializeError(error) })
package/src/errors.ts CHANGED
@@ -1,8 +1,31 @@
1
+ // Error codes for type checking without instanceof
2
+ export const ERROR_CODES = {
3
+ DURON_ERROR: 'DURON_ERROR',
4
+ STEP_ALREADY_EXECUTED: 'STEP_ALREADY_EXECUTED',
5
+ NON_RETRIABLE: 'NON_RETRIABLE',
6
+ ACTION_TIMEOUT: 'ACTION_TIMEOUT',
7
+ STEP_TIMEOUT: 'STEP_TIMEOUT',
8
+ ACTION_CANCEL: 'ACTION_CANCEL',
9
+ UNHANDLED_CHILD_STEPS: 'UNHANDLED_CHILD_STEPS',
10
+ } as const
11
+
12
+ export type ErrorCode = (typeof ERROR_CODES)[keyof typeof ERROR_CODES]
13
+
1
14
  /**
2
15
  * Base class for all built-in errors in Duron.
3
16
  * All errors include a cause property that can be serialized.
4
17
  */
5
18
  export abstract class DuronError extends Error {
19
+ /**
20
+ * Error code for type checking without instanceof.
21
+ */
22
+ public readonly code: ErrorCode = ERROR_CODES.DURON_ERROR
23
+
24
+ /**
25
+ * Whether this error should prevent retries.
26
+ */
27
+ public readonly nonRetriable: boolean = false
28
+
6
29
  /**
7
30
  * The underlying cause of the error, if any.
8
31
  *
@@ -36,6 +59,9 @@ export abstract class DuronError extends Error {
36
59
  * Error thrown when attempting to execute a step that has already been executed.
37
60
  */
38
61
  export class StepAlreadyExecutedError extends DuronError {
62
+ public override readonly code = ERROR_CODES.STEP_ALREADY_EXECUTED
63
+ public override readonly nonRetriable = true
64
+
39
65
  /**
40
66
  * Create a new StepAlreadyExecutedError.
41
67
  *
@@ -55,13 +81,17 @@ export class StepAlreadyExecutedError extends DuronError {
55
81
  * without retrying, even if retry options are configured.
56
82
  */
57
83
  export class NonRetriableError extends DuronError {
58
- // Constructor inherited from DuronError
84
+ public override readonly code: ErrorCode = ERROR_CODES.NON_RETRIABLE
85
+ public override readonly nonRetriable = true
59
86
  }
60
87
 
61
88
  /**
62
89
  * Error thrown when an action exceeds its timeout.
63
90
  */
64
91
  export class ActionTimeoutError extends DuronError {
92
+ public override readonly code = ERROR_CODES.ACTION_TIMEOUT
93
+ public override readonly nonRetriable = true
94
+
65
95
  /**
66
96
  * Create a new ActionTimeoutError.
67
97
  *
@@ -84,6 +114,9 @@ export class ActionTimeoutError extends DuronError {
84
114
  * Error thrown when a step exceeds its timeout.
85
115
  */
86
116
  export class StepTimeoutError extends DuronError {
117
+ public override readonly code = ERROR_CODES.STEP_TIMEOUT
118
+ public override readonly nonRetriable = false
119
+
87
120
  /**
88
121
  * Create a new StepTimeoutError.
89
122
  *
@@ -108,6 +141,9 @@ export class StepTimeoutError extends DuronError {
108
141
  * Error thrown when an action is cancelled.
109
142
  */
110
143
  export class ActionCancelError extends DuronError {
144
+ public override readonly code = ERROR_CODES.ACTION_CANCEL
145
+ public override readonly nonRetriable = true
146
+
111
147
  /**
112
148
  * Create a new ActionCancelError.
113
149
  *
@@ -133,6 +169,8 @@ export class ActionCancelError extends DuronError {
133
169
  * but not properly awaited. All child steps must be awaited before the parent returns.
134
170
  */
135
171
  export class UnhandledChildStepsError extends NonRetriableError {
172
+ public override readonly code = ERROR_CODES.UNHANDLED_CHILD_STEPS
173
+
136
174
  /**
137
175
  * The name of the parent step that completed with unhandled children.
138
176
  */
@@ -162,45 +200,44 @@ export class UnhandledChildStepsError extends NonRetriableError {
162
200
  * Checks if an error is a DuronError instance.
163
201
  */
164
202
  export function isDuronError(error: unknown): error is DuronError {
165
- return error instanceof DuronError
203
+ const code = (error as any)?.code
204
+ return code !== undefined && Object.values(ERROR_CODES).includes(code)
166
205
  }
167
206
 
168
207
  /**
169
208
  * Checks if an error is a NonRetriableError instance.
170
209
  */
171
210
  export function isNonRetriableError(error: unknown): error is NonRetriableError {
172
- return (
173
- error instanceof NonRetriableError ||
174
- error instanceof ActionCancelError ||
175
- error instanceof ActionTimeoutError ||
176
- error instanceof UnhandledChildStepsError
177
- )
211
+ return (error as any)?.nonRetriable === true
178
212
  }
179
213
 
180
214
  /**
181
215
  * Checks if an error is an UnhandledChildStepsError instance.
182
216
  */
183
217
  export function isUnhandledChildStepsError(error: unknown): error is UnhandledChildStepsError {
184
- return error instanceof UnhandledChildStepsError
218
+ return (error as any)?.code === ERROR_CODES.UNHANDLED_CHILD_STEPS
185
219
  }
186
220
 
187
221
  /**
188
222
  * Checks if an error is a timeout error (ActionTimeoutError or StepTimeoutError).
189
223
  */
190
224
  export function isTimeoutError(error: unknown): error is ActionTimeoutError | StepTimeoutError {
191
- return error instanceof ActionTimeoutError || error instanceof StepTimeoutError
225
+ const code = (error as any)?.code
226
+ return code === ERROR_CODES.ACTION_TIMEOUT || code === ERROR_CODES.STEP_TIMEOUT
192
227
  }
193
228
 
194
229
  /**
195
230
  * Checks if an error is a cancel error (ActionCancelError or StepCancelError).
196
231
  */
197
232
  export function isCancelError(error: unknown): error is ActionCancelError {
198
- return error instanceof ActionCancelError
233
+ return (error as any)?.code === ERROR_CODES.ACTION_CANCEL
199
234
  }
200
235
 
201
236
  export type SerializableError = {
202
237
  name: string
203
238
  message: string
239
+ code?: ErrorCode
240
+ nonRetriable?: boolean
204
241
  cause?: unknown
205
242
  stack?: string
206
243
  }
@@ -209,25 +246,27 @@ export type SerializableError = {
209
246
  * Serializes an error for storage in the database.
210
247
  * Handles DuronError instances specially to preserve their type information.
211
248
  */
212
- export function serializeError(error: unknown): {
213
- name: string
214
- message: string
215
- cause?: unknown
216
- stack?: string
217
- } {
218
- if (error instanceof StepTimeoutError || error instanceof ActionTimeoutError) {
249
+ export function serializeError(error: unknown): SerializableError {
250
+ const code = (error as any)?.code
251
+ const nonRetriable = (error as any)?.nonRetriable
252
+
253
+ if (isTimeoutError(error)) {
219
254
  return {
220
255
  name: error.name,
221
256
  message: error.message,
257
+ code,
258
+ nonRetriable,
222
259
  cause: error.cause,
223
260
  stack: undefined,
224
261
  }
225
262
  }
226
263
 
227
- if (error instanceof DuronError) {
264
+ if (isDuronError(error)) {
228
265
  return {
229
266
  name: error.name,
230
267
  message: error.message,
268
+ code,
269
+ nonRetriable,
231
270
  cause: error.cause,
232
271
  stack: error.stack,
233
272
  }
@@ -17,6 +17,7 @@ import {
17
17
  ActionCancelError,
18
18
  isCancelError,
19
19
  isNonRetriableError,
20
+ isTimeoutError,
20
21
  NonRetriableError,
21
22
  StepAlreadyExecutedError,
22
23
  StepTimeoutError,
@@ -493,6 +494,7 @@ export class StepManager {
493
494
  .catch(() => {
494
495
  trackedChild.settled = true
495
496
  // Swallow the error here - it will be re-thrown to the caller via the returned promise
497
+ // Note: sibling steps will be aborted when the error propagates to the action level
496
498
  })
497
499
 
498
500
  return childPromise
@@ -607,6 +609,15 @@ export class StepManager {
607
609
  if (!delayed) {
608
610
  throw new Error(`Failed to delay step "${name}" for job "${this.#jobId}" action "${this.#actionName}"`)
609
611
  }
612
+ } else {
613
+ if (isTimeoutError(error)) {
614
+ ;(error as any).nonRetriable = true
615
+ throw error
616
+ }
617
+ throw new NonRetriableError(
618
+ `Failed to execute step="${name}", jobId="${this.#jobId}", action="${this.#actionName}", parentStepId="${parentStepId}"`,
619
+ { cause: error },
620
+ )
610
621
  }
611
622
  },
612
623
  }).catch(async (error) => {
@@ -758,6 +769,7 @@ class ActionContext<TInput extends z.ZodObject, TOutput extends z.ZodObject, TVa
758
769
  ...this.#action.steps,
759
770
  ...options,
760
771
  })
772
+
761
773
  return this.#stepManager.push({
762
774
  name,
763
775
  cb,