duron 0.3.0-beta.10 → 0.3.0-beta.12

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.
Files changed (90) hide show
  1. package/dist/action-job.d.ts +33 -2
  2. package/dist/action-job.d.ts.map +1 -1
  3. package/dist/action-job.js +87 -22
  4. package/dist/action-manager.d.ts +44 -2
  5. package/dist/action-manager.d.ts.map +1 -1
  6. package/dist/action-manager.js +64 -3
  7. package/dist/action.d.ts +146 -3
  8. package/dist/action.d.ts.map +1 -1
  9. package/dist/action.js +131 -0
  10. package/dist/adapters/adapter.d.ts +365 -8
  11. package/dist/adapters/adapter.d.ts.map +1 -1
  12. package/dist/adapters/adapter.js +221 -15
  13. package/dist/adapters/postgres/base.d.ts +174 -5
  14. package/dist/adapters/postgres/base.d.ts.map +1 -1
  15. package/dist/adapters/postgres/base.js +349 -66
  16. package/dist/adapters/postgres/pglite.d.ts +37 -0
  17. package/dist/adapters/postgres/pglite.d.ts.map +1 -1
  18. package/dist/adapters/postgres/pglite.js +38 -0
  19. package/dist/adapters/postgres/postgres.d.ts +35 -0
  20. package/dist/adapters/postgres/postgres.d.ts.map +1 -1
  21. package/dist/adapters/postgres/postgres.js +42 -0
  22. package/dist/adapters/postgres/schema.d.ts +118 -35
  23. package/dist/adapters/postgres/schema.d.ts.map +1 -1
  24. package/dist/adapters/postgres/schema.default.d.ts +119 -36
  25. package/dist/adapters/postgres/schema.default.d.ts.map +1 -1
  26. package/dist/adapters/postgres/schema.default.js +2 -2
  27. package/dist/adapters/postgres/schema.js +55 -22
  28. package/dist/adapters/schemas.d.ts +107 -80
  29. package/dist/adapters/schemas.d.ts.map +1 -1
  30. package/dist/adapters/schemas.js +131 -26
  31. package/dist/client.d.ts +315 -9
  32. package/dist/client.d.ts.map +1 -1
  33. package/dist/client.js +391 -21
  34. package/dist/constants.js +6 -0
  35. package/dist/errors.d.ts +119 -0
  36. package/dist/errors.d.ts.map +1 -1
  37. package/dist/errors.js +111 -0
  38. package/dist/index.d.ts +1 -0
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/server.d.ts +91 -37
  41. package/dist/server.d.ts.map +1 -1
  42. package/dist/server.js +81 -25
  43. package/dist/step-manager.d.ts +111 -4
  44. package/dist/step-manager.d.ts.map +1 -1
  45. package/dist/step-manager.js +340 -69
  46. package/dist/telemetry/adapter.d.ts +322 -0
  47. package/dist/telemetry/adapter.d.ts.map +1 -1
  48. package/dist/telemetry/adapter.js +145 -0
  49. package/dist/telemetry/index.d.ts +1 -4
  50. package/dist/telemetry/index.d.ts.map +1 -1
  51. package/dist/telemetry/index.js +2 -4
  52. package/dist/telemetry/local-span-exporter.d.ts +56 -0
  53. package/dist/telemetry/local-span-exporter.d.ts.map +1 -0
  54. package/dist/telemetry/local-span-exporter.js +118 -0
  55. package/dist/telemetry/local.d.ts +48 -0
  56. package/dist/telemetry/local.d.ts.map +1 -1
  57. package/dist/telemetry/local.js +102 -0
  58. package/dist/telemetry/noop.d.ts +10 -0
  59. package/dist/telemetry/noop.d.ts.map +1 -1
  60. package/dist/telemetry/noop.js +43 -0
  61. package/dist/telemetry/opentelemetry.d.ts +23 -0
  62. package/dist/telemetry/opentelemetry.d.ts.map +1 -1
  63. package/dist/telemetry/opentelemetry.js +39 -0
  64. package/dist/utils/p-retry.d.ts +5 -0
  65. package/dist/utils/p-retry.d.ts.map +1 -1
  66. package/dist/utils/p-retry.js +8 -0
  67. package/dist/utils/wait-for-abort.d.ts +1 -0
  68. package/dist/utils/wait-for-abort.d.ts.map +1 -1
  69. package/dist/utils/wait-for-abort.js +1 -0
  70. package/migrations/postgres/{20260119153838_flimsy_thor_girl → 20260120154151_mean_magdalene}/migration.sql +27 -19
  71. package/migrations/postgres/{20260119153838_flimsy_thor_girl → 20260120154151_mean_magdalene}/snapshot.json +172 -65
  72. package/package.json +7 -2
  73. package/src/action-job.ts +32 -28
  74. package/src/action-manager.ts +5 -5
  75. package/src/action.ts +7 -7
  76. package/src/adapters/adapter.ts +54 -54
  77. package/src/adapters/postgres/base.ts +140 -77
  78. package/src/adapters/postgres/schema.default.ts +2 -2
  79. package/src/adapters/postgres/schema.ts +47 -23
  80. package/src/adapters/schemas.ts +83 -36
  81. package/src/client.ts +195 -42
  82. package/src/index.ts +1 -0
  83. package/src/server.ts +37 -37
  84. package/src/step-manager.ts +170 -86
  85. package/src/telemetry/index.ts +2 -20
  86. package/src/telemetry/local-span-exporter.ts +148 -0
  87. package/src/telemetry/adapter.ts +0 -642
  88. package/src/telemetry/local.ts +0 -429
  89. package/src/telemetry/noop.ts +0 -141
  90. package/src/telemetry/opentelemetry.ts +0 -453
@@ -1,7 +1,7 @@
1
+ import { type Tracer } from '@opentelemetry/api';
1
2
  import type { Logger } from 'pino';
2
3
  import type { Action } from './action.js';
3
4
  import type { Adapter } from './adapters/adapter.js';
4
- import type { TelemetryAdapter } from './telemetry/adapter.js';
5
5
  export interface ActionJobOptions<TAction extends Action<any, any, any>> {
6
6
  job: {
7
7
  id: string;
@@ -12,15 +12,46 @@ export interface ActionJobOptions<TAction extends Action<any, any, any>> {
12
12
  };
13
13
  action: TAction;
14
14
  database: Adapter;
15
- telemetry: TelemetryAdapter;
15
+ tracer: Tracer;
16
16
  variables: Record<string, unknown>;
17
17
  logger: Logger;
18
18
  }
19
+ /**
20
+ * ActionJob represents a single job execution for an action.
21
+ * Manages the execution lifecycle, timeout handling, and cancellation.
22
+ *
23
+ * @template TAction - The action type being executed
24
+ */
19
25
  export declare class ActionJob<TAction extends Action<any, any, any>> {
20
26
  #private;
27
+ /**
28
+ * Create a new ActionJob instance.
29
+ *
30
+ * @param options - Configuration options for the action job
31
+ */
21
32
  constructor(options: ActionJobOptions<TAction>);
33
+ /**
34
+ * Execute the action job.
35
+ * Creates the action context, sets up timeout, executes the handler,
36
+ * validates output, and marks the job as completed or failed.
37
+ *
38
+ * @returns Promise resolving to the action result
39
+ * @throws ActionTimeoutError if the job times out
40
+ * @throws ActionCancelError if the job is cancelled
41
+ * @throws Error if the job fails or output validation fails
42
+ */
22
43
  execute(): Promise<any>;
44
+ /**
45
+ * Wait for the job execution to complete.
46
+ * Returns a promise that resolves when the job finishes (successfully or with error).
47
+ *
48
+ * @returns Promise that resolves when the job is done
49
+ */
23
50
  waitForDone(): Promise<void>;
51
+ /**
52
+ * Cancel the job execution.
53
+ * Clears the timeout and aborts the action handler.
54
+ */
24
55
  cancel(): void;
25
56
  }
26
57
  //# sourceMappingURL=action-job.d.ts.map
@@ -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;IAkIb,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,EAAgD,KAAK,MAAM,EAAS,MAAM,oBAAoB,CAAA;AACrG,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;AAKpD,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,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAClC,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;;;GAKG;AACH,qBAAa,SAAS,CAAC,OAAO,SAAS,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;;IAkB1D;;;;OAIG;gBACS,OAAO,EAAE,gBAAgB,CAAC,OAAO,CAAC;IA4B9C;;;;;;;;;OASG;IACG,OAAO;IAgIb;;;;;OAKG;IACH,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B;;;OAGG;IACH,MAAM;CAmBP"}
@@ -1,11 +1,18 @@
1
+ import { context, SpanKind, SpanStatusCode, trace } from '@opentelemetry/api';
1
2
  import { ActionCancelError, ActionTimeoutError, isCancelError, isTimeoutError, serializeError } from './errors.js';
2
3
  import { StepManager } from './step-manager.js';
3
4
  import waitForAbort from './utils/wait-for-abort.js';
5
+ /**
6
+ * ActionJob represents a single job execution for an action.
7
+ * Manages the execution lifecycle, timeout handling, and cancellation.
8
+ *
9
+ * @template TAction - The action type being executed
10
+ */
4
11
  export class ActionJob {
5
12
  #job;
6
13
  #action;
7
14
  #database;
8
- #telemetry;
15
+ #tracer;
9
16
  #variables;
10
17
  #logger;
11
18
  #stepManager;
@@ -13,20 +20,29 @@ export class ActionJob {
13
20
  #timeoutId = null;
14
21
  #done;
15
22
  #resolve = null;
16
- #jobSpan = null;
23
+ #jobSpan;
24
+ // ============================================================================
25
+ // Constructor
26
+ // ============================================================================
27
+ /**
28
+ * Create a new ActionJob instance.
29
+ *
30
+ * @param options - Configuration options for the action job
31
+ */
17
32
  constructor(options) {
18
33
  this.#job = options.job;
19
34
  this.#action = options.action;
20
35
  this.#database = options.database;
21
- this.#telemetry = options.telemetry;
36
+ this.#tracer = options.tracer;
22
37
  this.#variables = options.variables;
23
38
  this.#logger = options.logger;
24
39
  this.#abortController = new AbortController();
40
+ // Create StepManager for this job
25
41
  this.#stepManager = new StepManager({
26
42
  jobId: options.job.id,
27
43
  actionName: options.job.actionName,
28
44
  adapter: options.database,
29
- telemetry: options.telemetry,
45
+ tracer: options.tracer,
30
46
  logger: options.logger,
31
47
  concurrencyLimit: options.action.steps.concurrency,
32
48
  });
@@ -34,31 +50,52 @@ export class ActionJob {
34
50
  this.#resolve = resolve;
35
51
  });
36
52
  }
53
+ // ============================================================================
54
+ // Public API Methods
55
+ // ============================================================================
56
+ /**
57
+ * Execute the action job.
58
+ * Creates the action context, sets up timeout, executes the handler,
59
+ * validates output, and marks the job as completed or failed.
60
+ *
61
+ * @returns Promise resolving to the action result
62
+ * @throws ActionTimeoutError if the job times out
63
+ * @throws ActionCancelError if the job is cancelled
64
+ * @throws Error if the job fails or output validation fails
65
+ */
37
66
  async execute() {
38
- this.#jobSpan = await this.#telemetry.startJobSpan({
39
- jobId: this.#job.id,
40
- actionName: this.#action.name,
41
- groupKey: this.#job.groupKey,
42
- input: this.#job.input,
67
+ // Start job span - uses no-op tracer if no SDK is configured
68
+ this.#jobSpan = this.#tracer.startSpan(`job:${this.#action.name}`, {
69
+ kind: SpanKind.INTERNAL,
70
+ attributes: {
71
+ 'duron.job.id': this.#job.id,
72
+ 'duron.action.name': this.#action.name,
73
+ 'duron.group.key': this.#job.groupKey,
74
+ },
43
75
  });
76
+ // Set the job span on the step manager
44
77
  this.#stepManager.setJobSpan(this.#jobSpan);
45
78
  try {
79
+ // Create a child logger for this job
46
80
  const jobLogger = this.#logger.child({
47
81
  jobId: this.#job.id,
48
82
  actionName: this.#action.name,
49
83
  });
50
- const observeContext = this.#telemetry.createObserveContext(this.#job.id, null, this.#jobSpan);
51
- const ctx = this.#stepManager.createActionContext(this.#job, this.#action, this.#variables, this.#abortController.signal, jobLogger, observeContext);
84
+ // Create action context with step manager
85
+ const ctx = this.#stepManager.createActionContext(this.#job, this.#action, this.#variables, this.#abortController.signal, jobLogger);
52
86
  this.#timeoutId = setTimeout(() => {
53
87
  const timeoutError = new ActionTimeoutError(this.#action.name, this.#job.id, this.#job.timeoutMs);
54
88
  this.#abortController.abort(timeoutError);
55
89
  }, this.#job.timeoutMs);
56
90
  this.#timeoutId?.unref?.();
91
+ // Execute handler with timeout - race between handler and abort signal
57
92
  const abortWaiter = waitForAbort(this.#abortController.signal);
58
93
  let result = null;
94
+ // Execute handler within the job span context so that child spans inherit the trace
95
+ const spanContext = trace.setSpan(context.active(), this.#jobSpan);
59
96
  await Promise.race([
60
- this.#action
61
- .handler(ctx)
97
+ context
98
+ .with(spanContext, () => this.#action.handler(ctx))
62
99
  .then((res) => {
63
100
  if (res !== undefined) {
64
101
  result = res;
@@ -69,42 +106,54 @@ export class ActionJob {
69
106
  }),
70
107
  abortWaiter.promise,
71
108
  ]);
109
+ // Validate output if schema is provided
72
110
  if (this.#action.output) {
73
111
  result = this.#action.output.parse(result, {
74
112
  error: () => 'Error parsing action output',
75
113
  reportInput: true,
76
114
  });
77
115
  }
116
+ // Complete job
78
117
  const completed = await this.#database.completeJob({ jobId: this.#job.id, output: result });
79
118
  if (!completed) {
80
119
  throw new Error('Job not completed');
81
120
  }
121
+ // Log action completion
82
122
  this.#logger.debug({ jobId: this.#job.id, actionName: this.#action.name }, '[ActionJob] Action finished executing');
83
- await this.#telemetry.endJobSpan(this.#jobSpan, { status: 'ok' });
123
+ // End job span successfully
124
+ this.#jobSpan.setStatus({ code: SpanStatusCode.OK });
125
+ this.#jobSpan.end();
84
126
  return result;
85
127
  }
86
128
  catch (error) {
129
+ // Abort all running steps when an error occurs
130
+ // This ensures cascading failure and stops any steps still running
87
131
  if (!this.#abortController.signal.aborted) {
88
132
  this.#abortController.abort(error);
89
133
  }
134
+ // Wait for step manager to drain (all steps to settle)
90
135
  await this.#stepManager.drain();
91
136
  if (isCancelError(error) ||
92
137
  (error instanceof Error && error.name === 'AbortError' && isCancelError(error.cause))) {
93
138
  this.#logger.warn({ jobId: this.#job.id, actionName: this.#action.name }, '[ActionJob] Job cancelled');
94
139
  await this.#database.cancelJob({ jobId: this.#job.id });
95
- if (this.#jobSpan) {
96
- await this.#telemetry.endJobSpan(this.#jobSpan, { status: 'cancelled' });
97
- }
140
+ // End job span as cancelled
141
+ this.#jobSpan.setStatus({ code: SpanStatusCode.ERROR, message: 'Job cancelled' });
142
+ this.#jobSpan.end();
98
143
  return;
99
144
  }
100
- const message = isTimeoutError(error)
101
- ? '[ActionJob] Job timed out'
102
- : '[ActionJob] Job failed';
145
+ const message = isTimeoutError(error) ? '[ActionJob] Job timed out' : '[ActionJob] Job failed';
103
146
  this.#logger.error({ jobId: this.#job.id, actionName: this.#action.name }, message);
104
147
  await this.#database.failJob({ jobId: this.#job.id, error: serializeError(error) });
105
- if (this.#jobSpan) {
106
- await this.#telemetry.endJobSpan(this.#jobSpan, { status: 'error', error });
148
+ // End job span with error
149
+ this.#jobSpan.setStatus({
150
+ code: SpanStatusCode.ERROR,
151
+ message: error instanceof Error ? error.message : String(error),
152
+ });
153
+ if (error instanceof Error) {
154
+ this.#jobSpan.recordException(error);
107
155
  }
156
+ this.#jobSpan.end();
108
157
  throw error;
109
158
  }
110
159
  finally {
@@ -112,14 +161,30 @@ export class ActionJob {
112
161
  this.#resolve?.();
113
162
  }
114
163
  }
164
+ /**
165
+ * Wait for the job execution to complete.
166
+ * Returns a promise that resolves when the job finishes (successfully or with error).
167
+ *
168
+ * @returns Promise that resolves when the job is done
169
+ */
115
170
  waitForDone() {
116
171
  return this.#done;
117
172
  }
173
+ /**
174
+ * Cancel the job execution.
175
+ * Clears the timeout and aborts the action handler.
176
+ */
118
177
  cancel() {
119
178
  this.#clear();
120
179
  const cancelError = new ActionCancelError(this.#action.name, this.#job.id);
121
180
  this.#abortController.abort(cancelError);
122
181
  }
182
+ // ============================================================================
183
+ // Private Methods
184
+ // ============================================================================
185
+ /**
186
+ * Clear the timeout timer.
187
+ */
123
188
  #clear() {
124
189
  if (this.#timeoutId) {
125
190
  clearTimeout(this.#timeoutId);
@@ -1,23 +1,65 @@
1
+ import type { Tracer } from '@opentelemetry/api';
1
2
  import type { Logger } from 'pino';
2
3
  import type { Action } from './action.js';
3
4
  import type { Adapter, Job } from './adapters/adapter.js';
4
- import type { TelemetryAdapter } from './telemetry/adapter.js';
5
5
  export interface ActionManagerOptions<TAction extends Action<any, any, any>> {
6
6
  action: TAction;
7
7
  database: Adapter;
8
- telemetry: TelemetryAdapter;
8
+ tracer: Tracer;
9
9
  variables: Record<string, unknown>;
10
10
  logger: Logger;
11
11
  concurrencyLimit: number;
12
12
  }
13
+ /**
14
+ * ActionManager manages the execution of jobs for a specific action.
15
+ * Uses a fastq queue to control concurrency and process jobs.
16
+ *
17
+ * @template TAction - The action type being managed
18
+ */
13
19
  export declare class ActionManager<TAction extends Action<any, any, any>> {
14
20
  #private;
21
+ /**
22
+ * Create a new ActionManager instance.
23
+ *
24
+ * @param options - Configuration options for the action manager
25
+ */
15
26
  constructor(options: ActionManagerOptions<TAction>);
27
+ /**
28
+ * Queue a job for execution.
29
+ *
30
+ * @param job - The job to queue
31
+ * @returns Promise that resolves when the job is queued
32
+ */
16
33
  push(job: Job): Promise<void>;
34
+ /**
35
+ * Cancel a specific job by ID.
36
+ *
37
+ * @param jobId - The ID of the job to cancel
38
+ * @returns If the manager has the job, it will be cancelled and true will be returned. Otherwise, false will be returned.
39
+ */
17
40
  cancelJob(jobId: string): boolean;
41
+ /**
42
+ * Cancel all active jobs.
43
+ */
18
44
  abortAll(): void;
45
+ /**
46
+ * Check if the queue is idle (no jobs being processed).
47
+ *
48
+ * @returns Promise resolving to `true` if idle, `false` otherwise
49
+ */
19
50
  idle(): Promise<boolean>;
51
+ /**
52
+ * Wait for the queue to drain (all jobs completed).
53
+ *
54
+ * @returns Promise that resolves when the queue is drained
55
+ */
20
56
  drain(): Promise<void>;
57
+ /**
58
+ * Stop the action manager.
59
+ * Aborts all active jobs and waits for the queue to drain.
60
+ *
61
+ * @returns Promise that resolves when the action manager is stopped
62
+ */
21
63
  stop(): Promise<void>;
22
64
  }
23
65
  //# sourceMappingURL=action-manager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"action-manager.d.ts","sourceRoot":"","sources":["../src/action-manager.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAElC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,OAAO,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAA;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAE9D,MAAM,WAAW,oBAAoB,CAAC,OAAO,SAAS,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACzE,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;IACd,gBAAgB,EAAE,MAAM,CAAA;CACzB;AAQD,qBAAa,aAAa,CAAC,OAAO,SAAS,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;;gBAoBlD,OAAO,EAAE,oBAAoB,CAAC,OAAO,CAAC;IA4B5C,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAUnC,SAAS,CAAC,KAAK,EAAE,MAAM;IAYvB,QAAQ,IAAI,IAAI;IAWV,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC;IASxB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAUtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CA+C5B"}
1
+ {"version":3,"file":"action-manager.d.ts","sourceRoot":"","sources":["../src/action-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAEhD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAElC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,OAAO,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAA;AAEzD,MAAM,WAAW,oBAAoB,CAAC,OAAO,SAAS,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACzE,MAAM,EAAE,OAAO,CAAA;IACf,QAAQ,EAAE,OAAO,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAClC,MAAM,EAAE,MAAM,CAAA;IACd,gBAAgB,EAAE,MAAM,CAAA;CACzB;AAED;;;;;GAKG;AACH,qBAAa,aAAa,CAAC,OAAO,SAAS,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;;IAe9D;;;;OAIG;gBACS,OAAO,EAAE,oBAAoB,CAAC,OAAO,CAAC;IAsBlD;;;;;OAKG;IACG,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAInC;;;;;OAKG;IACH,SAAS,CAAC,KAAK,EAAE,MAAM;IASvB;;OAEG;IACH,QAAQ,IAAI,IAAI;IAMhB;;;;OAIG;IACG,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC;IAI9B;;;;OAIG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B;;;;;OAKG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CA+C5B"}
@@ -1,22 +1,37 @@
1
1
  import fastq from 'fastq';
2
2
  import { ActionJob } from './action-job.js';
3
+ /**
4
+ * ActionManager manages the execution of jobs for a specific action.
5
+ * Uses a fastq queue to control concurrency and process jobs.
6
+ *
7
+ * @template TAction - The action type being managed
8
+ */
3
9
  export class ActionManager {
4
10
  #action;
5
11
  #database;
6
- #telemetry;
12
+ #tracer;
7
13
  #variables;
8
14
  #logger;
9
15
  #queue;
10
16
  #concurrencyLimit;
11
17
  #activeJobs = new Map();
12
18
  #stopped = false;
19
+ // ============================================================================
20
+ // Constructor
21
+ // ============================================================================
22
+ /**
23
+ * Create a new ActionManager instance.
24
+ *
25
+ * @param options - Configuration options for the action manager
26
+ */
13
27
  constructor(options) {
14
28
  this.#action = options.action;
15
29
  this.#database = options.database;
16
- this.#telemetry = options.telemetry;
30
+ this.#tracer = options.tracer;
17
31
  this.#variables = options.variables;
18
32
  this.#logger = options.logger;
19
33
  this.#concurrencyLimit = options.concurrencyLimit;
34
+ // Create fastq queue with action concurrency limit
20
35
  this.#queue = fastq.promise(async (job) => {
21
36
  if (this.#stopped) {
22
37
  return;
@@ -24,9 +39,24 @@ export class ActionManager {
24
39
  await this.#executeJob(job);
25
40
  }, this.#concurrencyLimit);
26
41
  }
42
+ // ============================================================================
43
+ // Public API Methods
44
+ // ============================================================================
45
+ /**
46
+ * Queue a job for execution.
47
+ *
48
+ * @param job - The job to queue
49
+ * @returns Promise that resolves when the job is queued
50
+ */
27
51
  async push(job) {
28
52
  return this.#queue.push(job);
29
53
  }
54
+ /**
55
+ * Cancel a specific job by ID.
56
+ *
57
+ * @param jobId - The ID of the job to cancel
58
+ * @returns If the manager has the job, it will be cancelled and true will be returned. Otherwise, false will be returned.
59
+ */
30
60
  cancelJob(jobId) {
31
61
  const actionJob = this.#activeJobs.get(jobId);
32
62
  if (actionJob) {
@@ -35,17 +65,36 @@ export class ActionManager {
35
65
  }
36
66
  return false;
37
67
  }
68
+ /**
69
+ * Cancel all active jobs.
70
+ */
38
71
  abortAll() {
39
72
  for (const actionJob of this.#activeJobs.values()) {
40
73
  actionJob.cancel();
41
74
  }
42
75
  }
76
+ /**
77
+ * Check if the queue is idle (no jobs being processed).
78
+ *
79
+ * @returns Promise resolving to `true` if idle, `false` otherwise
80
+ */
43
81
  async idle() {
44
82
  return this.#queue.idle();
45
83
  }
84
+ /**
85
+ * Wait for the queue to drain (all jobs completed).
86
+ *
87
+ * @returns Promise that resolves when the queue is drained
88
+ */
46
89
  async drain() {
47
90
  return this.#queue.drain();
48
91
  }
92
+ /**
93
+ * Stop the action manager.
94
+ * Aborts all active jobs and waits for the queue to drain.
95
+ *
96
+ * @returns Promise that resolves when the action manager is stopped
97
+ */
49
98
  async stop() {
50
99
  if (this.#stopped) {
51
100
  return;
@@ -55,7 +104,16 @@ export class ActionManager {
55
104
  await this.#queue.killAndDrain();
56
105
  await Promise.all(Array.from(this.#activeJobs.values()).map((actionJob) => actionJob.waitForDone()));
57
106
  }
107
+ // ============================================================================
108
+ // Private Methods
109
+ // ============================================================================
110
+ /**
111
+ * Execute a job by creating an ActionJob and running it.
112
+ *
113
+ * @param job - The job to execute
114
+ */
58
115
  async #executeJob(job) {
116
+ // Create ActionJob for this job
59
117
  const actionJob = new ActionJob({
60
118
  job: {
61
119
  id: job.id,
@@ -66,15 +124,18 @@ export class ActionManager {
66
124
  },
67
125
  action: this.#action,
68
126
  database: this.#database,
69
- telemetry: this.#telemetry,
127
+ tracer: this.#tracer,
70
128
  variables: this.#variables,
71
129
  logger: this.#logger,
72
130
  });
73
131
  this.#activeJobs.set(job.id, actionJob);
74
132
  try {
133
+ // Execute the job - all error handling is done inside ActionJob.execute()
75
134
  await actionJob.execute();
76
135
  }
77
136
  finally {
137
+ // Always cleanup, even if the job failed or was cancelled
138
+ // Errors are already handled in ActionJob.execute() (logging, failing job, etc.)
78
139
  this.#activeJobs.delete(job.id);
79
140
  }
80
141
  }