duron 0.2.2 → 0.3.0-beta.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.
Files changed (77) hide show
  1. package/dist/action-job.d.ts +2 -0
  2. package/dist/action-job.d.ts.map +1 -1
  3. package/dist/action-job.js +20 -1
  4. package/dist/action-manager.d.ts +2 -0
  5. package/dist/action-manager.d.ts.map +1 -1
  6. package/dist/action-manager.js +3 -0
  7. package/dist/action.d.ts +7 -0
  8. package/dist/action.d.ts.map +1 -1
  9. package/dist/action.js +1 -0
  10. package/dist/adapters/adapter.d.ts +10 -2
  11. package/dist/adapters/adapter.d.ts.map +1 -1
  12. package/dist/adapters/adapter.js +59 -1
  13. package/dist/adapters/postgres/base.d.ts +9 -4
  14. package/dist/adapters/postgres/base.d.ts.map +1 -1
  15. package/dist/adapters/postgres/base.js +269 -19
  16. package/dist/adapters/postgres/schema.d.ts +249 -105
  17. package/dist/adapters/postgres/schema.d.ts.map +1 -1
  18. package/dist/adapters/postgres/schema.default.d.ts +249 -106
  19. package/dist/adapters/postgres/schema.default.d.ts.map +1 -1
  20. package/dist/adapters/postgres/schema.default.js +2 -2
  21. package/dist/adapters/postgres/schema.js +29 -1
  22. package/dist/adapters/schemas.d.ts +140 -7
  23. package/dist/adapters/schemas.d.ts.map +1 -1
  24. package/dist/adapters/schemas.js +52 -4
  25. package/dist/client.d.ts +8 -1
  26. package/dist/client.d.ts.map +1 -1
  27. package/dist/client.js +28 -0
  28. package/dist/errors.d.ts +6 -0
  29. package/dist/errors.d.ts.map +1 -1
  30. package/dist/errors.js +16 -1
  31. package/dist/index.d.ts +3 -1
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +3 -1
  34. package/dist/server.d.ts +220 -16
  35. package/dist/server.d.ts.map +1 -1
  36. package/dist/server.js +123 -8
  37. package/dist/step-manager.d.ts +8 -2
  38. package/dist/step-manager.d.ts.map +1 -1
  39. package/dist/step-manager.js +138 -15
  40. package/dist/telemetry/adapter.d.ts +85 -0
  41. package/dist/telemetry/adapter.d.ts.map +1 -0
  42. package/dist/telemetry/adapter.js +128 -0
  43. package/dist/telemetry/index.d.ts +5 -0
  44. package/dist/telemetry/index.d.ts.map +1 -0
  45. package/dist/telemetry/index.js +4 -0
  46. package/dist/telemetry/local.d.ts +21 -0
  47. package/dist/telemetry/local.d.ts.map +1 -0
  48. package/dist/telemetry/local.js +180 -0
  49. package/dist/telemetry/noop.d.ts +16 -0
  50. package/dist/telemetry/noop.d.ts.map +1 -0
  51. package/dist/telemetry/noop.js +39 -0
  52. package/dist/telemetry/opentelemetry.d.ts +24 -0
  53. package/dist/telemetry/opentelemetry.d.ts.map +1 -0
  54. package/dist/telemetry/opentelemetry.js +202 -0
  55. package/migrations/postgres/20260117231749_clumsy_penance/migration.sql +3 -0
  56. package/migrations/postgres/20260117231749_clumsy_penance/snapshot.json +988 -0
  57. package/migrations/postgres/20260118202533_wealthy_mysterio/migration.sql +24 -0
  58. package/migrations/postgres/20260118202533_wealthy_mysterio/snapshot.json +1362 -0
  59. package/package.json +6 -4
  60. package/src/action-job.ts +35 -0
  61. package/src/action-manager.ts +5 -0
  62. package/src/action.ts +56 -0
  63. package/src/adapters/adapter.ts +151 -0
  64. package/src/adapters/postgres/base.ts +342 -23
  65. package/src/adapters/postgres/schema.default.ts +2 -2
  66. package/src/adapters/postgres/schema.ts +49 -1
  67. package/src/adapters/schemas.ts +81 -5
  68. package/src/client.ts +78 -0
  69. package/src/errors.ts +45 -1
  70. package/src/index.ts +3 -1
  71. package/src/server.ts +163 -8
  72. package/src/step-manager.ts +232 -13
  73. package/src/telemetry/adapter.ts +468 -0
  74. package/src/telemetry/index.ts +17 -0
  75. package/src/telemetry/local.ts +336 -0
  76. package/src/telemetry/noop.ts +95 -0
  77. package/src/telemetry/opentelemetry.ts +310 -0
@@ -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, } from './errors.js';
4
+ import { ActionCancelError, isCancelError, isNonRetriableError, NonRetriableError, StepAlreadyExecutedError, StepTimeoutError, serializeError, UnhandledChildStepsError, } from './errors.js';
5
5
  import pRetry from './utils/p-retry.js';
6
6
  import waitForAbort from './utils/wait-for-abort.js';
7
7
  export class StepStore {
@@ -9,13 +9,15 @@ export class StepStore {
9
9
  constructor(adapter) {
10
10
  this.#adapter = adapter;
11
11
  }
12
- async getOrCreate(jobId, name, timeoutMs, retriesLimit) {
12
+ async getOrCreate(jobId, name, timeoutMs, retriesLimit, parentStepId = null, parallel = false) {
13
13
  try {
14
14
  return await this.#adapter.createOrRecoverJobStep({
15
15
  jobId,
16
16
  name,
17
17
  timeoutMs,
18
18
  retriesLimit,
19
+ parentStepId,
20
+ parallel,
19
21
  });
20
22
  }
21
23
  catch (error) {
@@ -42,24 +44,48 @@ export class StepManager {
42
44
  #jobId;
43
45
  #actionName;
44
46
  #stepStore;
47
+ #telemetry;
45
48
  #queue;
46
49
  #logger;
47
50
  #historySteps = new Set();
51
+ #stepSpans = new Map();
52
+ #jobSpan = null;
48
53
  constructor(options) {
49
54
  this.#jobId = options.jobId;
50
55
  this.#actionName = options.actionName;
51
56
  this.#logger = options.logger;
57
+ this.#telemetry = options.telemetry;
52
58
  this.#stepStore = new StepStore(options.adapter);
53
59
  this.#queue = fastq.promise(async (task) => {
54
60
  if (this.#historySteps.has(task.name)) {
55
61
  throw new StepAlreadyExecutedError(task.name, this.#jobId, this.#actionName);
56
62
  }
57
63
  this.#historySteps.add(task.name);
58
- return this.#executeStep(task.name, task.cb, task.options, task.abortSignal);
64
+ return this.#executeStep(task.name, task.cb, task.options, task.abortSignal, task.parentStepId, task.parallel);
59
65
  }, options.concurrencyLimit);
60
66
  }
61
- createActionContext(job, action, variables, abortSignal, logger) {
62
- return new ActionContext(this, job, action, variables, abortSignal, logger);
67
+ setJobSpan(span) {
68
+ this.#jobSpan = span;
69
+ }
70
+ createActionContext(job, action, variables, abortSignal, logger, observeContext) {
71
+ return new ActionContext(this, job, action, variables, abortSignal, logger, observeContext);
72
+ }
73
+ createStepObserveContext(stepId) {
74
+ const stepSpan = this.#stepSpans.get(stepId);
75
+ if (stepSpan) {
76
+ return this.#telemetry.createObserveContext(this.#jobId, stepId, stepSpan);
77
+ }
78
+ if (this.#jobSpan) {
79
+ return this.#telemetry.createObserveContext(this.#jobId, stepId, this.#jobSpan);
80
+ }
81
+ return {
82
+ recordMetric: () => {
83
+ },
84
+ addSpanAttribute: () => {
85
+ },
86
+ addSpanEvent: () => {
87
+ },
88
+ };
63
89
  }
64
90
  async push(task) {
65
91
  return this.#queue.push(task);
@@ -67,7 +93,7 @@ export class StepManager {
67
93
  async drain() {
68
94
  await this.#queue.drain();
69
95
  }
70
- async #executeStep(name, cb, options, abortSignal) {
96
+ async #executeStep(name, cb, options, abortSignal, parentStepId, parallel) {
71
97
  const expire = options.expire;
72
98
  const retryOptions = options.retry;
73
99
  let step = null;
@@ -76,16 +102,25 @@ export class StepManager {
76
102
  if (abortSignal.aborted) {
77
103
  throw new ActionCancelError(this.#actionName, this.#jobId, { cause: 'step cancelled before create step' });
78
104
  }
79
- const newStep = await this.#stepStore.getOrCreate(this.#jobId, name, expire, retryOptions.limit);
105
+ const newStep = await this.#stepStore.getOrCreate(this.#jobId, name, expire, retryOptions.limit, parentStepId, parallel);
80
106
  if (!newStep) {
81
107
  throw new NonRetriableError(`Failed to create step "${name}" for job "${this.#jobId}" action "${this.#actionName}"`, { cause: 'step not created' });
82
108
  }
83
109
  step = newStep;
110
+ const parentSpan = parentStepId ? this.#stepSpans.get(parentStepId) : this.#jobSpan;
111
+ const stepSpan = await this.#telemetry.startStepSpan({
112
+ jobId: this.#jobId,
113
+ stepId: step.id,
114
+ stepName: name,
115
+ parentSpan: parentSpan ?? undefined,
116
+ parentStepId,
117
+ });
118
+ this.#stepSpans.set(step.id, stepSpan);
84
119
  if (abortSignal.aborted) {
85
120
  throw new ActionCancelError(this.#actionName, this.#jobId, { cause: 'step cancelled after create step' });
86
121
  }
87
122
  if (step.status === STEP_STATUS_COMPLETED) {
88
- this.#logger.debug({ jobId: this.#jobId, actionName: this.#actionName, stepName: name, stepId: step.id }, '[StepManager] Step recovered (already completed)');
123
+ this.#logger.debug({ jobId: this.#jobId, actionName: this.#actionName, stepName: name, stepId: step.id, parentStepId }, '[StepManager] Step recovered (already completed)');
89
124
  return step.output;
90
125
  }
91
126
  else if (step.status === STEP_STATUS_FAILED) {
@@ -96,7 +131,7 @@ export class StepManager {
96
131
  else if (step.status === STEP_STATUS_CANCELLED) {
97
132
  throw new NonRetriableError(`Cannot recover a cancelled step "${name}" for job "${this.#jobId}" action "${this.#actionName}"`, { cause: step.error });
98
133
  }
99
- this.#logger.debug({ jobId: this.#jobId, actionName: this.#actionName, stepName: name, stepId: step.id }, '[StepManager] Step started executing');
134
+ this.#logger.debug({ jobId: this.#jobId, actionName: this.#actionName, stepName: name, stepId: step.id, parentStepId }, '[StepManager] Step started executing');
100
135
  }
101
136
  const stepAbortController = new AbortController();
102
137
  const timeoutId = setTimeout(() => {
@@ -104,13 +139,54 @@ export class StepManager {
104
139
  stepAbortController.abort(timeoutError);
105
140
  }, expire);
106
141
  timeoutId?.unref?.();
107
- const signal = AbortSignal.any([abortSignal, stepAbortController.signal]);
142
+ const stepSignal = AbortSignal.any([abortSignal, stepAbortController.signal]);
143
+ const childSteps = [];
144
+ const childAbortController = new AbortController();
145
+ const childSignal = AbortSignal.any([stepSignal, childAbortController.signal]);
146
+ const stepObserveContext = this.createStepObserveContext(step.id);
147
+ const stepContext = {
148
+ signal: stepSignal,
149
+ stepId: step.id,
150
+ parentStepId,
151
+ observe: stepObserveContext,
152
+ step: (childName, childCb, childOptions = {}) => {
153
+ const { parallel: _parentParallel, ...inheritableOptions } = options;
154
+ const parsedChildOptions = StepOptionsSchema.parse({
155
+ ...inheritableOptions,
156
+ ...childOptions,
157
+ });
158
+ const childPromise = this.push({
159
+ name: childName,
160
+ cb: childCb,
161
+ options: parsedChildOptions,
162
+ abortSignal: childSignal,
163
+ parentStepId: step.id,
164
+ parallel: parsedChildOptions.parallel,
165
+ });
166
+ const trackedChild = {
167
+ promise: childPromise,
168
+ settled: false,
169
+ };
170
+ childSteps.push(trackedChild);
171
+ childPromise
172
+ .then(() => {
173
+ trackedChild.settled = true;
174
+ })
175
+ .catch(() => {
176
+ trackedChild.settled = true;
177
+ });
178
+ return childPromise;
179
+ },
180
+ };
108
181
  try {
109
- const abortPromise = waitForAbort(signal);
110
- const callbackPromise = cb({ signal });
182
+ const abortPromise = waitForAbort(stepSignal);
183
+ const callbackPromise = cb(stepContext);
111
184
  let result = null;
185
+ let aborted = false;
112
186
  await Promise.race([
113
- abortPromise.promise,
187
+ abortPromise.promise.then(() => {
188
+ aborted = true;
189
+ }),
114
190
  callbackPromise
115
191
  .then((res) => {
116
192
  if (res !== undefined && res !== null) {
@@ -121,10 +197,35 @@ export class StepManager {
121
197
  abortPromise.release();
122
198
  }),
123
199
  ]);
200
+ if (aborted) {
201
+ if (childSteps.length > 0) {
202
+ await Promise.allSettled(childSteps.map((c) => c.promise));
203
+ }
204
+ throw stepSignal.reason;
205
+ }
206
+ const unsettledChildren = childSteps.filter((c) => !c.settled);
207
+ if (unsettledChildren.length > 0) {
208
+ this.#logger.warn({
209
+ jobId: this.#jobId,
210
+ actionName: this.#actionName,
211
+ stepName: name,
212
+ stepId: step.id,
213
+ pendingCount: unsettledChildren.length,
214
+ }, '[StepManager] Parent step completed with unhandled child steps - aborting children');
215
+ const unhandledError = new UnhandledChildStepsError(name, unsettledChildren.length);
216
+ childAbortController.abort(unhandledError);
217
+ await Promise.allSettled(unsettledChildren.map((c) => c.promise));
218
+ throw unhandledError;
219
+ }
124
220
  const completed = await this.#stepStore.updateStatus(step.id, 'completed', result);
125
221
  if (!completed) {
126
222
  throw new Error(`Failed to complete step "${name}" for job "${this.#jobId}" action "${this.#actionName}"`);
127
223
  }
224
+ const stepSpan = this.#stepSpans.get(step.id);
225
+ if (stepSpan) {
226
+ await this.#telemetry.endStepSpan(stepSpan, { status: 'ok' });
227
+ this.#stepSpans.delete(step.id);
228
+ }
128
229
  this.#logger.debug({ jobId: this.#jobId, actionName: this.#actionName, stepName: name, stepId: step.id }, '[StepManager] Step finished executing');
129
230
  return result;
130
231
  }
@@ -155,6 +256,16 @@ export class StepManager {
155
256
  },
156
257
  }).catch(async (error) => {
157
258
  if (step) {
259
+ const stepSpan = this.#stepSpans.get(step.id);
260
+ if (stepSpan) {
261
+ if (isCancelError(error)) {
262
+ await this.#telemetry.endStepSpan(stepSpan, { status: 'cancelled' });
263
+ }
264
+ else {
265
+ await this.#telemetry.endStepSpan(stepSpan, { status: 'error', error });
266
+ }
267
+ this.#stepSpans.delete(step.id);
268
+ }
158
269
  if (isCancelError(error)) {
159
270
  await this.#stepStore.updateStatus(step.id, 'cancelled');
160
271
  }
@@ -175,7 +286,8 @@ class ActionContext {
175
286
  #jobId;
176
287
  #groupKey = '@default';
177
288
  #action;
178
- constructor(stepManager, job, action, variables, abortSignal, logger) {
289
+ #observeContext;
290
+ constructor(stepManager, job, action, variables, abortSignal, logger, observeContext) {
179
291
  this.#stepManager = stepManager;
180
292
  this.#variables = variables;
181
293
  this.#abortSignal = abortSignal;
@@ -183,6 +295,7 @@ class ActionContext {
183
295
  this.#action = action;
184
296
  this.#jobId = job.id;
185
297
  this.#groupKey = job.groupKey ?? '@default';
298
+ this.#observeContext = observeContext;
186
299
  if (action.input) {
187
300
  this.#input = action.input.parse(job.input, {
188
301
  error: () => 'Error parsing action input',
@@ -207,11 +320,21 @@ class ActionContext {
207
320
  get logger() {
208
321
  return this.#logger;
209
322
  }
323
+ get observe() {
324
+ return this.#observeContext;
325
+ }
210
326
  async step(name, cb, options = {}) {
211
327
  const parsedOptions = StepOptionsSchema.parse({
212
328
  ...this.#action.steps,
213
329
  ...options,
214
330
  });
215
- return this.#stepManager.push({ name, cb, options: parsedOptions, abortSignal: this.#abortSignal });
331
+ return this.#stepManager.push({
332
+ name,
333
+ cb,
334
+ options: parsedOptions,
335
+ abortSignal: this.#abortSignal,
336
+ parentStepId: null,
337
+ parallel: parsedOptions.parallel,
338
+ });
216
339
  }
217
340
  }
@@ -0,0 +1,85 @@
1
+ import type { Logger } from 'pino';
2
+ import type { Adapter } from '../adapters/adapter.js';
3
+ export interface TelemetryClient {
4
+ database: Adapter;
5
+ }
6
+ export interface Span {
7
+ id: string;
8
+ jobId: string;
9
+ stepId: string | null;
10
+ parentSpanId: string | null;
11
+ }
12
+ export interface StartJobSpanOptions {
13
+ jobId: string;
14
+ actionName: string;
15
+ groupKey: string;
16
+ input?: any;
17
+ }
18
+ export interface StartStepSpanOptions {
19
+ jobId: string;
20
+ stepId: string;
21
+ stepName: string;
22
+ parentSpan?: Span;
23
+ parentStepId: string | null;
24
+ }
25
+ export interface EndSpanOptions {
26
+ status: 'ok' | 'error' | 'cancelled';
27
+ error?: any;
28
+ }
29
+ export interface StartDatabaseSpanOptions {
30
+ operation: string;
31
+ query?: string;
32
+ }
33
+ export interface RecordMetricOptions {
34
+ jobId: string;
35
+ stepId?: string;
36
+ name: string;
37
+ value: number;
38
+ attributes?: Record<string, any>;
39
+ }
40
+ export interface AddSpanEventOptions {
41
+ span: Span;
42
+ name: string;
43
+ attributes?: Record<string, any>;
44
+ }
45
+ export interface AddSpanAttributeOptions {
46
+ span: Span;
47
+ key: string;
48
+ value: string | number | boolean;
49
+ }
50
+ export interface ObserveContext {
51
+ recordMetric(name: string, value: number, attributes?: Record<string, any>): void;
52
+ addSpanAttribute(key: string, value: string | number | boolean): void;
53
+ addSpanEvent(name: string, attributes?: Record<string, any>): void;
54
+ }
55
+ export declare abstract class TelemetryAdapter {
56
+ #private;
57
+ start(): Promise<boolean>;
58
+ stop(): Promise<boolean>;
59
+ setLogger(logger: Logger): void;
60
+ get logger(): Logger | null;
61
+ setClient(client: TelemetryClient): void;
62
+ protected get client(): TelemetryClient | null;
63
+ startJobSpan(options: StartJobSpanOptions): Promise<Span>;
64
+ endJobSpan(span: Span, options: EndSpanOptions): Promise<void>;
65
+ startStepSpan(options: StartStepSpanOptions): Promise<Span>;
66
+ endStepSpan(span: Span, options: EndSpanOptions): Promise<void>;
67
+ startDatabaseSpan(options: StartDatabaseSpanOptions): Promise<Span | null>;
68
+ endDatabaseSpan(span: Span | null, options: EndSpanOptions): Promise<void>;
69
+ recordMetric(options: RecordMetricOptions): Promise<void>;
70
+ addSpanEvent(options: AddSpanEventOptions): Promise<void>;
71
+ addSpanAttribute(options: AddSpanAttributeOptions): Promise<void>;
72
+ createObserveContext(jobId: string, stepId: string | null, span: Span): ObserveContext;
73
+ protected abstract _start(): Promise<void>;
74
+ protected abstract _stop(): Promise<void>;
75
+ protected abstract _startJobSpan(options: StartJobSpanOptions): Promise<Span>;
76
+ protected abstract _endJobSpan(span: Span, options: EndSpanOptions): Promise<void>;
77
+ protected abstract _startStepSpan(options: StartStepSpanOptions): Promise<Span>;
78
+ protected abstract _endStepSpan(span: Span, options: EndSpanOptions): Promise<void>;
79
+ protected abstract _startDatabaseSpan(options: StartDatabaseSpanOptions): Promise<Span | null>;
80
+ protected abstract _endDatabaseSpan(span: Span, options: EndSpanOptions): Promise<void>;
81
+ protected abstract _recordMetric(options: RecordMetricOptions): Promise<void>;
82
+ protected abstract _addSpanEvent(options: AddSpanEventOptions): Promise<void>;
83
+ protected abstract _addSpanAttribute(options: AddSpanAttributeOptions): Promise<void>;
84
+ }
85
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/telemetry/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAElC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAA;AAUrD,MAAM,WAAW,eAAe;IAI9B,QAAQ,EAAE,OAAO,CAAA;CAClB;AAKD,MAAM,WAAW,IAAI;IAInB,EAAE,EAAE,MAAM,CAAA;IAKV,KAAK,EAAE,MAAM,CAAA;IAKb,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IAKrB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5B;AAKD,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,GAAG,CAAA;CACZ;AAKD,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,CAAC,EAAE,IAAI,CAAA;IACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5B;AAKD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,IAAI,GAAG,OAAO,GAAG,WAAW,CAAA;IACpC,KAAK,CAAC,EAAE,GAAG,CAAA;CACZ;AAKD,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAKD,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CACjC;AAKD,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,IAAI,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CACjC;AAKD,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,IAAI,CAAA;IACV,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;CACjC;AAKD,MAAM,WAAW,cAAc;IAQ7B,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAA;IAQjF,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAA;IAQrE,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAA;CACnE;AAUD,8BAAsB,gBAAgB;;IAkB9B,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC;IAkCzB,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC;IAiC9B,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAS/B,IAAI,MAAM,IAAI,MAAM,GAAG,IAAI,CAE1B;IAQD,SAAS,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI;IAUxC,SAAS,KAAK,MAAM,IAAI,eAAe,GAAG,IAAI,CAE7C;IAYK,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAWzD,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAW9D,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IAW3D,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAW/D,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAW1E,eAAe,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAe1E,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAUzD,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAUzD,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBvE,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,IAAI,EAAE,IAAI,GAAG,cAAc;IAiCtF,SAAS,CAAC,QAAQ,CAAC,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAK1C,SAAS,CAAC,QAAQ,CAAC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAKzC,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAK7E,SAAS,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAKlF,SAAS,CAAC,QAAQ,CAAC,cAAc,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IAK/E,SAAS,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAKnF,SAAS,CAAC,QAAQ,CAAC,kBAAkB,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAK9F,SAAS,CAAC,QAAQ,CAAC,gBAAgB,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAKvF,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAK7E,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAK7E,SAAS,CAAC,QAAQ,CAAC,iBAAiB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;CACtF"}
@@ -0,0 +1,128 @@
1
+ export class TelemetryAdapter {
2
+ #logger = null;
3
+ #client = null;
4
+ #started = false;
5
+ #stopped = false;
6
+ #starting = null;
7
+ #stopping = null;
8
+ async start() {
9
+ try {
10
+ if (this.#stopping || this.#stopped) {
11
+ return false;
12
+ }
13
+ if (this.#started) {
14
+ return true;
15
+ }
16
+ if (this.#starting) {
17
+ return this.#starting;
18
+ }
19
+ this.#starting = (async () => {
20
+ await this._start();
21
+ this.#started = true;
22
+ this.#starting = null;
23
+ return true;
24
+ })();
25
+ return this.#starting;
26
+ }
27
+ catch (error) {
28
+ this.#logger?.error(error, 'Error in TelemetryAdapter.start()');
29
+ throw error;
30
+ }
31
+ }
32
+ async stop() {
33
+ try {
34
+ if (this.#stopped) {
35
+ return true;
36
+ }
37
+ if (this.#stopping) {
38
+ return this.#stopping;
39
+ }
40
+ this.#stopping = (async () => {
41
+ await this._stop();
42
+ this.#stopped = true;
43
+ this.#stopping = null;
44
+ return true;
45
+ })();
46
+ return this.#stopping;
47
+ }
48
+ catch (error) {
49
+ this.#logger?.error(error, 'Error in TelemetryAdapter.stop()');
50
+ throw error;
51
+ }
52
+ }
53
+ setLogger(logger) {
54
+ this.#logger = logger;
55
+ }
56
+ get logger() {
57
+ return this.#logger;
58
+ }
59
+ setClient(client) {
60
+ this.#client = client;
61
+ }
62
+ get client() {
63
+ return this.#client;
64
+ }
65
+ async startJobSpan(options) {
66
+ await this.start();
67
+ return this._startJobSpan(options);
68
+ }
69
+ async endJobSpan(span, options) {
70
+ await this.start();
71
+ return this._endJobSpan(span, options);
72
+ }
73
+ async startStepSpan(options) {
74
+ await this.start();
75
+ return this._startStepSpan(options);
76
+ }
77
+ async endStepSpan(span, options) {
78
+ await this.start();
79
+ return this._endStepSpan(span, options);
80
+ }
81
+ async startDatabaseSpan(options) {
82
+ await this.start();
83
+ return this._startDatabaseSpan(options);
84
+ }
85
+ async endDatabaseSpan(span, options) {
86
+ if (!span)
87
+ return;
88
+ await this.start();
89
+ return this._endDatabaseSpan(span, options);
90
+ }
91
+ async recordMetric(options) {
92
+ await this.start();
93
+ return this._recordMetric(options);
94
+ }
95
+ async addSpanEvent(options) {
96
+ await this.start();
97
+ return this._addSpanEvent(options);
98
+ }
99
+ async addSpanAttribute(options) {
100
+ await this.start();
101
+ return this._addSpanAttribute(options);
102
+ }
103
+ createObserveContext(jobId, stepId, span) {
104
+ return {
105
+ recordMetric: (name, value, attributes) => {
106
+ this.recordMetric({
107
+ jobId,
108
+ stepId: stepId ?? undefined,
109
+ name,
110
+ value,
111
+ attributes,
112
+ }).catch((err) => {
113
+ this.#logger?.error(err, 'Error recording metric');
114
+ });
115
+ },
116
+ addSpanAttribute: (key, value) => {
117
+ this.addSpanAttribute({ span, key, value }).catch((err) => {
118
+ this.#logger?.error(err, 'Error adding span attribute');
119
+ });
120
+ },
121
+ addSpanEvent: (name, attributes) => {
122
+ this.addSpanEvent({ span, name, attributes }).catch((err) => {
123
+ this.#logger?.error(err, 'Error adding span event');
124
+ });
125
+ },
126
+ };
127
+ }
128
+ }
@@ -0,0 +1,5 @@
1
+ export { type AddSpanAttributeOptions, type AddSpanEventOptions, type EndSpanOptions, type ObserveContext, type RecordMetricOptions, type Span, type StartDatabaseSpanOptions, type StartJobSpanOptions, type StartStepSpanOptions, TelemetryAdapter, } from './adapter.js';
2
+ export { LocalTelemetryAdapter, type LocalTelemetryAdapterOptions, localTelemetryAdapter } from './local.js';
3
+ export { NoopTelemetryAdapter, noopTelemetryAdapter } from './noop.js';
4
+ export { OpenTelemetryAdapter, type OpenTelemetryAdapterOptions, openTelemetryAdapter } from './opentelemetry.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/telemetry/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACxB,KAAK,IAAI,EACT,KAAK,wBAAwB,EAC7B,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,gBAAgB,GACjB,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,qBAAqB,EAAE,KAAK,4BAA4B,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAC5G,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AACtE,OAAO,EAAE,oBAAoB,EAAE,KAAK,2BAA2B,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA"}
@@ -0,0 +1,4 @@
1
+ export { TelemetryAdapter, } from './adapter.js';
2
+ export { LocalTelemetryAdapter, localTelemetryAdapter } from './local.js';
3
+ export { NoopTelemetryAdapter, noopTelemetryAdapter } from './noop.js';
4
+ export { OpenTelemetryAdapter, openTelemetryAdapter } from './opentelemetry.js';
@@ -0,0 +1,21 @@
1
+ import { type AddSpanAttributeOptions, type AddSpanEventOptions, type EndSpanOptions, type RecordMetricOptions, type Span, type StartDatabaseSpanOptions, type StartJobSpanOptions, type StartStepSpanOptions, TelemetryAdapter } from './adapter.js';
2
+ export interface LocalTelemetryAdapterOptions {
3
+ flushDelayMs?: number;
4
+ }
5
+ export declare class LocalTelemetryAdapter extends TelemetryAdapter {
6
+ #private;
7
+ constructor(options?: LocalTelemetryAdapterOptions);
8
+ protected _start(): Promise<void>;
9
+ protected _stop(): Promise<void>;
10
+ protected _startJobSpan(options: StartJobSpanOptions): Promise<Span>;
11
+ protected _endJobSpan(span: Span, options: EndSpanOptions): Promise<void>;
12
+ protected _startStepSpan(options: StartStepSpanOptions): Promise<Span>;
13
+ protected _endStepSpan(span: Span, options: EndSpanOptions): Promise<void>;
14
+ protected _startDatabaseSpan(_options: StartDatabaseSpanOptions): Promise<Span | null>;
15
+ protected _endDatabaseSpan(_span: Span, _options: EndSpanOptions): Promise<void>;
16
+ protected _recordMetric(options: RecordMetricOptions): Promise<void>;
17
+ protected _addSpanEvent(options: AddSpanEventOptions): Promise<void>;
18
+ protected _addSpanAttribute(options: AddSpanAttributeOptions): Promise<void>;
19
+ }
20
+ export declare const localTelemetryAdapter: (options?: LocalTelemetryAdapterOptions) => LocalTelemetryAdapter;
21
+ //# sourceMappingURL=local.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../src/telemetry/local.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACxB,KAAK,IAAI,EACT,KAAK,wBAAwB,EAC7B,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,gBAAgB,EACjB,MAAM,cAAc,CAAA;AAMrB,MAAM,WAAW,4BAA4B;IAM3C,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AA4BD,qBAAa,qBAAsB,SAAQ,gBAAgB;;gBAO7C,OAAO,CAAC,EAAE,4BAA4B;cAwFlC,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;cAIvB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;cAUtB,aAAa,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;cAyB1D,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;cAoB/D,cAAc,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;cA2B5D,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;cAqBhE,kBAAkB,CAAC,QAAQ,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;cAK5E,gBAAgB,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;cAQtE,aAAa,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;cAW1D,aAAa,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;cAc1D,iBAAiB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;CAcnF;AA6BD,eAAO,MAAM,qBAAqB,GAAI,UAAU,4BAA4B,0BAAuC,CAAA"}