duron 0.2.1 → 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.
- package/dist/action-job.d.ts +2 -0
- package/dist/action-job.d.ts.map +1 -1
- package/dist/action-job.js +20 -1
- package/dist/action-manager.d.ts +2 -0
- package/dist/action-manager.d.ts.map +1 -1
- package/dist/action-manager.js +3 -0
- package/dist/action.d.ts +7 -0
- package/dist/action.d.ts.map +1 -1
- package/dist/action.js +1 -0
- package/dist/adapters/adapter.d.ts +10 -2
- package/dist/adapters/adapter.d.ts.map +1 -1
- package/dist/adapters/adapter.js +59 -1
- package/dist/adapters/postgres/base.d.ts +9 -4
- package/dist/adapters/postgres/base.d.ts.map +1 -1
- package/dist/adapters/postgres/base.js +269 -19
- package/dist/adapters/postgres/schema.d.ts +249 -105
- package/dist/adapters/postgres/schema.d.ts.map +1 -1
- package/dist/adapters/postgres/schema.default.d.ts +249 -106
- package/dist/adapters/postgres/schema.default.d.ts.map +1 -1
- package/dist/adapters/postgres/schema.default.js +2 -2
- package/dist/adapters/postgres/schema.js +29 -1
- package/dist/adapters/schemas.d.ts +140 -7
- package/dist/adapters/schemas.d.ts.map +1 -1
- package/dist/adapters/schemas.js +52 -4
- package/dist/client.d.ts +8 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +29 -1
- package/dist/errors.d.ts +6 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +16 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/server.d.ts +220 -16
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +123 -8
- package/dist/step-manager.d.ts +8 -2
- package/dist/step-manager.d.ts.map +1 -1
- package/dist/step-manager.js +138 -15
- package/dist/telemetry/adapter.d.ts +85 -0
- package/dist/telemetry/adapter.d.ts.map +1 -0
- package/dist/telemetry/adapter.js +128 -0
- package/dist/telemetry/index.d.ts +5 -0
- package/dist/telemetry/index.d.ts.map +1 -0
- package/dist/telemetry/index.js +4 -0
- package/dist/telemetry/local.d.ts +21 -0
- package/dist/telemetry/local.d.ts.map +1 -0
- package/dist/telemetry/local.js +180 -0
- package/dist/telemetry/noop.d.ts +16 -0
- package/dist/telemetry/noop.d.ts.map +1 -0
- package/dist/telemetry/noop.js +39 -0
- package/dist/telemetry/opentelemetry.d.ts +24 -0
- package/dist/telemetry/opentelemetry.d.ts.map +1 -0
- package/dist/telemetry/opentelemetry.js +202 -0
- package/migrations/postgres/20260117231749_clumsy_penance/migration.sql +3 -0
- package/migrations/postgres/20260117231749_clumsy_penance/snapshot.json +988 -0
- package/migrations/postgres/20260118202533_wealthy_mysterio/migration.sql +24 -0
- package/migrations/postgres/20260118202533_wealthy_mysterio/snapshot.json +1362 -0
- package/package.json +6 -4
- package/src/action-job.ts +35 -0
- package/src/action-manager.ts +5 -0
- package/src/action.ts +56 -0
- package/src/adapters/adapter.ts +151 -0
- package/src/adapters/postgres/base.ts +342 -23
- package/src/adapters/postgres/schema.default.ts +2 -2
- package/src/adapters/postgres/schema.ts +49 -1
- package/src/adapters/schemas.ts +81 -5
- package/src/client.ts +80 -2
- package/src/errors.ts +45 -1
- package/src/index.ts +3 -1
- package/src/server.ts +163 -8
- package/src/step-manager.ts +232 -13
- package/src/telemetry/adapter.ts +468 -0
- package/src/telemetry/index.ts +17 -0
- package/src/telemetry/local.ts +336 -0
- package/src/telemetry/noop.ts +95 -0
- package/src/telemetry/opentelemetry.ts +310 -0
package/dist/step-manager.js
CHANGED
|
@@ -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
|
-
|
|
62
|
-
|
|
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
|
|
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(
|
|
110
|
-
const callbackPromise = cb(
|
|
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
|
-
|
|
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({
|
|
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":"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"}
|
|
@@ -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"}
|