@ultrst-armada/krnl 1.0.8 → 1.0.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.
- package/README.md +15 -0
- package/package.json +1 -1
- package/packages/cli/dist/bin/krnl.cjs +2 -0
- package/packages/cli/dist/bin/krnl.js +1 -1
- package/packages/cli/dist/{chunk-3DD775A7.js → chunk-OOVZPIMX.js} +2 -0
- package/packages/cli/dist/index.cjs +2 -0
- package/packages/cli/dist/index.js +1 -1
- package/packages/core/dist/index.cjs +358 -57
- package/packages/core/dist/index.d.cts +150 -1
- package/packages/core/dist/index.d.ts +150 -1
- package/packages/core/dist/index.js +354 -57
- package/packages/core/package.json +1 -1
|
@@ -50,6 +50,7 @@ __export(index_exports, {
|
|
|
50
50
|
ServiceRegistry: () => ServiceRegistry,
|
|
51
51
|
ServiceRuntime: () => ServiceRuntime,
|
|
52
52
|
ServiceStateStore: () => ServiceStateStore,
|
|
53
|
+
TelemetryController: () => TelemetryController,
|
|
53
54
|
UdpProtocolAdapter: () => UdpProtocolAdapter,
|
|
54
55
|
WebSocketProtocolAdapter: () => WebSocketProtocolAdapter,
|
|
55
56
|
WorkerExecutionBoundary: () => WorkerExecutionBoundary,
|
|
@@ -58,7 +59,10 @@ __export(index_exports, {
|
|
|
58
59
|
createServiceDefinition: () => createServiceDefinition,
|
|
59
60
|
createServiceFacade: () => createServiceFacade,
|
|
60
61
|
createServiceProxy: () => createServiceProxy,
|
|
62
|
+
deltaResources: () => deltaResources,
|
|
61
63
|
gutts: () => gutts,
|
|
64
|
+
sampleResources: () => sampleResources,
|
|
65
|
+
telemetryNow: () => telemetryNow,
|
|
62
66
|
validateOrchestrationDAG: () => validateOrchestrationDAG,
|
|
63
67
|
validateServiceDefinition: () => validateServiceDefinition
|
|
64
68
|
});
|
|
@@ -128,6 +132,227 @@ var LifecycleManager = class {
|
|
|
128
132
|
}
|
|
129
133
|
};
|
|
130
134
|
|
|
135
|
+
// src/telemetry/TelemetryController.ts
|
|
136
|
+
var import_node_crypto = require("crypto");
|
|
137
|
+
|
|
138
|
+
// src/telemetry/TelemetryResources.ts
|
|
139
|
+
var runtimeProcess = typeof globalThis !== "undefined" ? globalThis.process : void 0;
|
|
140
|
+
var runtimePerformance = typeof globalThis !== "undefined" ? globalThis.performance : void 0;
|
|
141
|
+
function telemetryNow() {
|
|
142
|
+
return runtimePerformance?.now ? runtimePerformance.now() : Date.now();
|
|
143
|
+
}
|
|
144
|
+
function sampleResources() {
|
|
145
|
+
const memory = runtimeProcess?.memoryUsage?.();
|
|
146
|
+
const cpu = runtimeProcess?.cpuUsage?.();
|
|
147
|
+
const eventLoop = runtimePerformance?.eventLoopUtilization?.();
|
|
148
|
+
return {
|
|
149
|
+
cpuUserMicros: cpu?.user,
|
|
150
|
+
cpuSystemMicros: cpu?.system,
|
|
151
|
+
heapUsedBytes: memory?.heapUsed,
|
|
152
|
+
heapTotalBytes: memory?.heapTotal,
|
|
153
|
+
rssBytes: memory?.rss,
|
|
154
|
+
externalBytes: memory?.external,
|
|
155
|
+
arrayBuffersBytes: memory?.arrayBuffers,
|
|
156
|
+
eventLoopUtilization: eventLoop?.utilization,
|
|
157
|
+
scope: memory || cpu || eventLoop ? "process" : "runtime"
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
function deltaResources(start, end) {
|
|
161
|
+
const delta = (a, b) => a === void 0 || b === void 0 ? void 0 : b - a;
|
|
162
|
+
return {
|
|
163
|
+
cpuUserMicros: delta(start.cpuUserMicros, end.cpuUserMicros),
|
|
164
|
+
cpuSystemMicros: delta(start.cpuSystemMicros, end.cpuSystemMicros),
|
|
165
|
+
heapUsedBytes: delta(start.heapUsedBytes, end.heapUsedBytes),
|
|
166
|
+
heapTotalBytes: delta(start.heapTotalBytes, end.heapTotalBytes),
|
|
167
|
+
rssBytes: delta(start.rssBytes, end.rssBytes),
|
|
168
|
+
externalBytes: delta(start.externalBytes, end.externalBytes),
|
|
169
|
+
arrayBuffersBytes: delta(start.arrayBuffersBytes, end.arrayBuffersBytes),
|
|
170
|
+
eventLoopUtilization: delta(start.eventLoopUtilization, end.eventLoopUtilization),
|
|
171
|
+
scope: start.scope
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// src/telemetry/TelemetryController.ts
|
|
176
|
+
var id = (prefix) => `${prefix}_${(0, import_node_crypto.randomUUID)()}`;
|
|
177
|
+
function percentiles(values) {
|
|
178
|
+
if (!values.length) return { min: 0, mean: 0, p50: 0, p90: 0, p95: 0, p99: 0, max: 0 };
|
|
179
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
180
|
+
const pick = (p) => sorted[Math.min(sorted.length - 1, Math.floor((sorted.length - 1) * p))];
|
|
181
|
+
return {
|
|
182
|
+
min: sorted[0],
|
|
183
|
+
mean: sorted.reduce((sum, value) => sum + value, 0) / sorted.length,
|
|
184
|
+
p50: pick(0.5),
|
|
185
|
+
p90: pick(0.9),
|
|
186
|
+
p95: pick(0.95),
|
|
187
|
+
p99: pick(0.99),
|
|
188
|
+
max: sorted[sorted.length - 1]
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
var TelemetryController = class {
|
|
192
|
+
constructor(serviceId, options = {}) {
|
|
193
|
+
this.serviceId = serviceId;
|
|
194
|
+
this.mode = options.mode ?? "off";
|
|
195
|
+
this.maxSamples = Math.max(1, options.maxSamples ?? 2048);
|
|
196
|
+
this.maxRecentInvocations = Math.max(1, options.maxRecentInvocations ?? 100);
|
|
197
|
+
}
|
|
198
|
+
serviceId;
|
|
199
|
+
mode;
|
|
200
|
+
maxSamples;
|
|
201
|
+
maxRecentInvocations;
|
|
202
|
+
samples = [];
|
|
203
|
+
active = /* @__PURE__ */ new Map();
|
|
204
|
+
totalInvocationCount = 0;
|
|
205
|
+
totalSuccessCount = 0;
|
|
206
|
+
totalErrorCount = 0;
|
|
207
|
+
lastInvocationAt;
|
|
208
|
+
enable(mode = "standard") {
|
|
209
|
+
this.mode = mode;
|
|
210
|
+
}
|
|
211
|
+
disable() {
|
|
212
|
+
this.mode = "off";
|
|
213
|
+
this.active.clear();
|
|
214
|
+
}
|
|
215
|
+
setMode(mode) {
|
|
216
|
+
this.mode = mode;
|
|
217
|
+
if (mode === "off") this.active.clear();
|
|
218
|
+
}
|
|
219
|
+
getMode() {
|
|
220
|
+
return this.mode;
|
|
221
|
+
}
|
|
222
|
+
status() {
|
|
223
|
+
return {
|
|
224
|
+
enabled: this.mode !== "off",
|
|
225
|
+
mode: this.mode,
|
|
226
|
+
serviceId: this.serviceId,
|
|
227
|
+
invocationCount: this.totalInvocationCount,
|
|
228
|
+
activeInvocations: this.active.size,
|
|
229
|
+
lastInvocationAt: this.lastInvocationAt
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
begin(target, kind, correlationId, parentSpanId) {
|
|
233
|
+
if (this.mode === "off") {
|
|
234
|
+
return {
|
|
235
|
+
invocationId: "",
|
|
236
|
+
traceId: "",
|
|
237
|
+
spanId: "",
|
|
238
|
+
parentSpanId,
|
|
239
|
+
end: () => void 0
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
const invocationId = id("inv");
|
|
243
|
+
const spanId = id("span");
|
|
244
|
+
const traceId = parentSpanId ? this.findTraceId(parentSpanId) ?? id("trace") : id("trace");
|
|
245
|
+
const active = {
|
|
246
|
+
invocationId,
|
|
247
|
+
traceId,
|
|
248
|
+
spanId,
|
|
249
|
+
parentSpanId,
|
|
250
|
+
serviceId: this.serviceId,
|
|
251
|
+
target,
|
|
252
|
+
kind,
|
|
253
|
+
correlationId,
|
|
254
|
+
startedAt: telemetryNow(),
|
|
255
|
+
resourcesStart: this.mode === "standard" ? void 0 : sampleResources()
|
|
256
|
+
};
|
|
257
|
+
this.active.set(invocationId, active);
|
|
258
|
+
return {
|
|
259
|
+
invocationId,
|
|
260
|
+
traceId,
|
|
261
|
+
spanId,
|
|
262
|
+
parentSpanId,
|
|
263
|
+
end: (error) => this.finish(active, error)
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
reset() {
|
|
267
|
+
this.samples.length = 0;
|
|
268
|
+
this.active.clear();
|
|
269
|
+
this.totalInvocationCount = 0;
|
|
270
|
+
this.totalSuccessCount = 0;
|
|
271
|
+
this.totalErrorCount = 0;
|
|
272
|
+
this.lastInvocationAt = void 0;
|
|
273
|
+
}
|
|
274
|
+
snapshot() {
|
|
275
|
+
const invocations = this.samples.slice();
|
|
276
|
+
const durations = invocations.map((item) => item.durationMs);
|
|
277
|
+
const targetMap = /* @__PURE__ */ new Map();
|
|
278
|
+
for (const invocation of invocations) {
|
|
279
|
+
const key = `${invocation.kind}:${invocation.target}`;
|
|
280
|
+
const group = targetMap.get(key) ?? [];
|
|
281
|
+
group.push(invocation);
|
|
282
|
+
targetMap.set(key, group);
|
|
283
|
+
}
|
|
284
|
+
const targets = [...targetMap.values()].map((group) => ({
|
|
285
|
+
target: group[0].target,
|
|
286
|
+
kind: group[0].kind,
|
|
287
|
+
count: group.length,
|
|
288
|
+
successCount: group.filter((item) => item.status === "completed").length,
|
|
289
|
+
errorCount: group.filter((item) => item.status === "failed").length,
|
|
290
|
+
durationMs: percentiles(group.map((item) => item.durationMs)),
|
|
291
|
+
lastInvocationAt: group[group.length - 1]?.completedAt
|
|
292
|
+
}));
|
|
293
|
+
return {
|
|
294
|
+
serviceId: this.serviceId,
|
|
295
|
+
mode: this.mode,
|
|
296
|
+
capturedAt: Date.now(),
|
|
297
|
+
status: this.status(),
|
|
298
|
+
totals: {
|
|
299
|
+
invocationCount: this.totalInvocationCount,
|
|
300
|
+
successCount: this.totalSuccessCount,
|
|
301
|
+
errorCount: this.totalErrorCount,
|
|
302
|
+
durationMs: percentiles(durations)
|
|
303
|
+
},
|
|
304
|
+
targets,
|
|
305
|
+
activeInvocations: this.active.size,
|
|
306
|
+
recentInvocations: invocations.slice(-this.maxRecentInvocations)
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
functionality(name) {
|
|
310
|
+
return this.snapshot().targets.find((target) => target.kind === "functionality" && target.target === name);
|
|
311
|
+
}
|
|
312
|
+
functionalities() {
|
|
313
|
+
return this.snapshot().targets.filter((target) => target.kind === "functionality");
|
|
314
|
+
}
|
|
315
|
+
findTraceId(parentSpanId) {
|
|
316
|
+
for (let index = this.samples.length - 1; index >= 0; index -= 1) {
|
|
317
|
+
if (this.samples[index].spanId === parentSpanId) return this.samples[index].traceId;
|
|
318
|
+
}
|
|
319
|
+
for (const active of this.active.values()) {
|
|
320
|
+
if (active.spanId === parentSpanId) return active.traceId;
|
|
321
|
+
}
|
|
322
|
+
return void 0;
|
|
323
|
+
}
|
|
324
|
+
finish(active, error) {
|
|
325
|
+
if (!this.active.delete(active.invocationId)) return;
|
|
326
|
+
const completedAt = telemetryNow();
|
|
327
|
+
const resourcesEnd = this.mode === "standard" ? void 0 : sampleResources();
|
|
328
|
+
const invocation = {
|
|
329
|
+
invocationId: active.invocationId,
|
|
330
|
+
traceId: active.traceId,
|
|
331
|
+
spanId: active.spanId,
|
|
332
|
+
parentSpanId: active.parentSpanId,
|
|
333
|
+
serviceId: active.serviceId,
|
|
334
|
+
target: active.target,
|
|
335
|
+
kind: active.kind,
|
|
336
|
+
correlationId: active.correlationId,
|
|
337
|
+
startedAt: active.startedAt,
|
|
338
|
+
completedAt,
|
|
339
|
+
durationMs: Math.max(0, completedAt - active.startedAt),
|
|
340
|
+
status: error === void 0 ? "completed" : "failed",
|
|
341
|
+
error: error === void 0 ? void 0 : {
|
|
342
|
+
name: error instanceof Error ? error.name : "Error",
|
|
343
|
+
message: error instanceof Error ? error.message : String(error)
|
|
344
|
+
},
|
|
345
|
+
resources: active.resourcesStart && resourcesEnd ? { start: active.resourcesStart, end: resourcesEnd, delta: deltaResources(active.resourcesStart, resourcesEnd) } : void 0
|
|
346
|
+
};
|
|
347
|
+
this.samples.push(invocation);
|
|
348
|
+
this.totalInvocationCount += 1;
|
|
349
|
+
if (invocation.status === "completed") this.totalSuccessCount += 1;
|
|
350
|
+
else this.totalErrorCount += 1;
|
|
351
|
+
if (this.samples.length > this.maxSamples) this.samples.splice(0, this.samples.length - this.maxSamples);
|
|
352
|
+
this.lastInvocationAt = Date.now();
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
|
|
131
356
|
// src/services/ServiceInstance.ts
|
|
132
357
|
var ServiceInstance = class {
|
|
133
358
|
constructor(definition) {
|
|
@@ -135,6 +360,7 @@ var ServiceInstance = class {
|
|
|
135
360
|
this.id = definition.id;
|
|
136
361
|
this.name = definition.name;
|
|
137
362
|
this.version = definition.version;
|
|
363
|
+
this.telemetry = new TelemetryController(this.id);
|
|
138
364
|
this.lifecycle = new LifecycleManager();
|
|
139
365
|
if (definition.state) {
|
|
140
366
|
this.stateStore = new ServiceStateStore(definition.state.initial);
|
|
@@ -144,6 +370,7 @@ var ServiceInstance = class {
|
|
|
144
370
|
id;
|
|
145
371
|
name;
|
|
146
372
|
version;
|
|
373
|
+
telemetry;
|
|
147
374
|
stateStore;
|
|
148
375
|
lifecycle;
|
|
149
376
|
initialized = false;
|
|
@@ -208,7 +435,19 @@ var ServiceInstance = class {
|
|
|
208
435
|
if (!operation) {
|
|
209
436
|
throw new Error("[Service:" + this.name + "] Operation '" + op + "' not found.");
|
|
210
437
|
}
|
|
211
|
-
|
|
438
|
+
if (ctx.metadata?.__krnlTelemetryInternal === true) {
|
|
439
|
+
return await operation.handler(input, ctx);
|
|
440
|
+
}
|
|
441
|
+
const parentSpanId = typeof ctx.metadata?.__krnlTelemetryParentSpanId === "string" ? ctx.metadata.__krnlTelemetryParentSpanId : void 0;
|
|
442
|
+
const handle = this.telemetry.begin(op, "service", ctx.correlationId, parentSpanId);
|
|
443
|
+
try {
|
|
444
|
+
const output = await operation.handler(input, ctx);
|
|
445
|
+
handle.end();
|
|
446
|
+
return output;
|
|
447
|
+
} catch (error) {
|
|
448
|
+
handle.end(error);
|
|
449
|
+
throw error;
|
|
450
|
+
}
|
|
212
451
|
}
|
|
213
452
|
getState() {
|
|
214
453
|
return this.stateStore?.getState() ?? Object.freeze({});
|
|
@@ -240,6 +479,7 @@ var ServiceProxy = class {
|
|
|
240
479
|
this.id = definition.id;
|
|
241
480
|
this.name = definition.name;
|
|
242
481
|
this.version = definition.version;
|
|
482
|
+
this.telemetry = new TelemetryController(this.id);
|
|
243
483
|
this.stateCache = { ...definition.state?.initial ?? {} };
|
|
244
484
|
}
|
|
245
485
|
definition;
|
|
@@ -248,6 +488,7 @@ var ServiceProxy = class {
|
|
|
248
488
|
id;
|
|
249
489
|
name;
|
|
250
490
|
version;
|
|
491
|
+
telemetry;
|
|
251
492
|
stateCache;
|
|
252
493
|
eventHandlers = /* @__PURE__ */ new Map();
|
|
253
494
|
lifecycle = new LifecycleManager();
|
|
@@ -305,11 +546,21 @@ var ServiceProxy = class {
|
|
|
305
546
|
payload: input,
|
|
306
547
|
timestamp: Date.now()
|
|
307
548
|
};
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
|
|
549
|
+
const parentSpanId = typeof ctx.metadata?.__krnlTelemetryParentSpanId === "string" ? ctx.metadata.__krnlTelemetryParentSpanId : void 0;
|
|
550
|
+
const handle = this.telemetry.begin(op, "service", ctx.correlationId, parentSpanId);
|
|
551
|
+
try {
|
|
552
|
+
const response = await this.adapter.send(this.endpoint, envelope);
|
|
553
|
+
if (response.error) {
|
|
554
|
+
const error = new Error("[ServiceProxy:" + this.name + "] Remote error: " + response.error);
|
|
555
|
+
handle.end(error);
|
|
556
|
+
throw error;
|
|
557
|
+
}
|
|
558
|
+
handle.end();
|
|
559
|
+
return response.payload;
|
|
560
|
+
} catch (error) {
|
|
561
|
+
handle.end(error);
|
|
562
|
+
throw error;
|
|
311
563
|
}
|
|
312
|
-
return response.payload;
|
|
313
564
|
}
|
|
314
565
|
getState() {
|
|
315
566
|
return Object.freeze({ ...this.stateCache });
|
|
@@ -457,22 +708,22 @@ var FunctionalityFacade = class {
|
|
|
457
708
|
definition;
|
|
458
709
|
eventBus;
|
|
459
710
|
events;
|
|
460
|
-
constructor(
|
|
461
|
-
if (!
|
|
711
|
+
constructor(id2, definition, options = {}) {
|
|
712
|
+
if (!id2 || typeof id2 !== "string") {
|
|
462
713
|
throw new Error("[FunctionalityFacade] Functionality id must be a non-empty string.");
|
|
463
714
|
}
|
|
464
715
|
if (!definition || typeof definition.execute !== "function") {
|
|
465
|
-
throw new Error(`[FunctionalityFacade:${
|
|
716
|
+
throw new Error(`[FunctionalityFacade:${id2}] Functionality must define execute().`);
|
|
466
717
|
}
|
|
467
|
-
this.id =
|
|
468
|
-
this.name = definition.name ||
|
|
718
|
+
this.id = id2;
|
|
719
|
+
this.name = definition.name || id2;
|
|
469
720
|
this.description = definition.description || "";
|
|
470
721
|
this.bubbleEvents = options.bubbleEvents ?? definition.bubbleEvents ?? true;
|
|
471
722
|
this.definition = definition;
|
|
472
723
|
this.eventBus = new EventBus();
|
|
473
724
|
for (const reserved of ["triggered", "completed", "failed"]) {
|
|
474
725
|
if (definition.events && reserved in definition.events) {
|
|
475
|
-
throw new Error(`[FunctionalityFacade:${
|
|
726
|
+
throw new Error(`[FunctionalityFacade:${id2}] Event '${reserved}' is reserved for functionality lifecycle.`);
|
|
476
727
|
}
|
|
477
728
|
}
|
|
478
729
|
const eventNames = [
|
|
@@ -586,11 +837,11 @@ var PriorityQueue = class {
|
|
|
586
837
|
return item.run;
|
|
587
838
|
}
|
|
588
839
|
enqueue(run, options) {
|
|
589
|
-
const { priority = 0, id } = options ?? {};
|
|
840
|
+
const { priority = 0, id: id2 } = options ?? {};
|
|
590
841
|
const { size } = this;
|
|
591
842
|
const element = {
|
|
592
843
|
priority,
|
|
593
|
-
id,
|
|
844
|
+
id: id2,
|
|
594
845
|
run
|
|
595
846
|
};
|
|
596
847
|
if (size === 0) {
|
|
@@ -607,16 +858,16 @@ var PriorityQueue = class {
|
|
|
607
858
|
const index = lowerBound(this.#queue, element, (a, b) => a.priority === b.priority ? 0 : b.priority - a.priority);
|
|
608
859
|
this.#queue.splice(index, 0, element);
|
|
609
860
|
}
|
|
610
|
-
setPriority(
|
|
611
|
-
const index = this.#findIndex((element) => element.id ===
|
|
861
|
+
setPriority(id2, priority) {
|
|
862
|
+
const index = this.#findIndex((element) => element.id === id2);
|
|
612
863
|
if (index === -1) {
|
|
613
|
-
throw new ReferenceError(`No promise function with the id "${
|
|
864
|
+
throw new ReferenceError(`No promise function with the id "${id2}" exists in the queue.`);
|
|
614
865
|
}
|
|
615
866
|
if (this.#queue[index].priority === priority) {
|
|
616
867
|
return;
|
|
617
868
|
}
|
|
618
869
|
const [item] = this.#queue.splice(index, 1);
|
|
619
|
-
this.enqueue(item.run, { priority, id });
|
|
870
|
+
this.enqueue(item.run, { priority, id: id2 });
|
|
620
871
|
}
|
|
621
872
|
remove(idOrRun) {
|
|
622
873
|
const index = this.#findIndex((element) => (typeof idOrRun === "string" ? element.id : element.run) === idOrRun);
|
|
@@ -1032,17 +1283,17 @@ var PQueue = class extends EventTarget {
|
|
|
1032
1283
|
}
|
|
1033
1284
|
}
|
|
1034
1285
|
async #add(function_, options, waitingTask) {
|
|
1035
|
-
const
|
|
1286
|
+
const id2 = options.id ?? (this.#idAssigner++).toString();
|
|
1036
1287
|
options = {
|
|
1037
1288
|
timeout: this.#timeout,
|
|
1038
1289
|
...options,
|
|
1039
|
-
id
|
|
1290
|
+
id: id2
|
|
1040
1291
|
};
|
|
1041
1292
|
validateTimeout(options.timeout);
|
|
1042
1293
|
if (options.priority !== void 0 && (typeof options.priority !== "number" || Number.isNaN(options.priority))) {
|
|
1043
1294
|
throw new TypeError(`Expected \`priority\` to be a number, got \`${String(options.priority)}\` (${typeof options.priority})`);
|
|
1044
1295
|
}
|
|
1045
|
-
waitingTask.id =
|
|
1296
|
+
waitingTask.id = id2;
|
|
1046
1297
|
waitingTask.priority = options.priority ?? 0;
|
|
1047
1298
|
return new Promise((resolve, reject) => {
|
|
1048
1299
|
if (options.signal?.aborted) {
|
|
@@ -1059,7 +1310,7 @@ var PQueue = class extends EventTarget {
|
|
|
1059
1310
|
}
|
|
1060
1311
|
this.#pending++;
|
|
1061
1312
|
const runningTask = {
|
|
1062
|
-
id,
|
|
1313
|
+
id: id2,
|
|
1063
1314
|
priority: waitingTask.priority,
|
|
1064
1315
|
startTime: Date.now(),
|
|
1065
1316
|
timeout: options.timeout
|
|
@@ -1126,7 +1377,7 @@ var PQueue = class extends EventTarget {
|
|
|
1126
1377
|
if (this.#queue instanceof PriorityQueue) {
|
|
1127
1378
|
this.#queue.remove(run);
|
|
1128
1379
|
} else {
|
|
1129
|
-
this.#queue.remove(
|
|
1380
|
+
this.#queue.remove(id2);
|
|
1130
1381
|
}
|
|
1131
1382
|
reject(signal.reason);
|
|
1132
1383
|
this.#processQueue();
|
|
@@ -1202,18 +1453,18 @@ var PQueue = class extends EventTarget {
|
|
|
1202
1453
|
// '🦀' runs last
|
|
1203
1454
|
```
|
|
1204
1455
|
*/
|
|
1205
|
-
setPriority(
|
|
1456
|
+
setPriority(id2, priority) {
|
|
1206
1457
|
if (typeof priority !== "number" || !Number.isFinite(priority)) {
|
|
1207
1458
|
throw new TypeError(`Expected \`priority\` to be a finite number, got \`${priority}\` (${typeof priority})`);
|
|
1208
1459
|
}
|
|
1209
1460
|
for (const waitingTask of this.#waitingTasks) {
|
|
1210
|
-
if (waitingTask.id ===
|
|
1211
|
-
this.#queue.setPriority(
|
|
1461
|
+
if (waitingTask.id === id2) {
|
|
1462
|
+
this.#queue.setPriority(id2, priority);
|
|
1212
1463
|
waitingTask.priority = priority;
|
|
1213
1464
|
return;
|
|
1214
1465
|
}
|
|
1215
1466
|
}
|
|
1216
|
-
throw new ReferenceError(`No promise function with the id "${
|
|
1467
|
+
throw new ReferenceError(`No promise function with the id "${id2}" exists in the queue.`);
|
|
1217
1468
|
}
|
|
1218
1469
|
/**
|
|
1219
1470
|
Adds a sync or async task to the queue.
|
|
@@ -1556,7 +1807,7 @@ var TimeoutError = class extends DOMException {
|
|
|
1556
1807
|
};
|
|
1557
1808
|
|
|
1558
1809
|
// src/orchestration/canonical/KrnlQ.ts
|
|
1559
|
-
var
|
|
1810
|
+
var import_node_crypto2 = require("crypto");
|
|
1560
1811
|
|
|
1561
1812
|
// src/orchestration/canonical/model.ts
|
|
1562
1813
|
function validateOrchestrationDAG(steps) {
|
|
@@ -1623,8 +1874,8 @@ function validateOrchestrationDAG(steps) {
|
|
|
1623
1874
|
}
|
|
1624
1875
|
}
|
|
1625
1876
|
const queue = [];
|
|
1626
|
-
for (const [
|
|
1627
|
-
if (deg === 0) queue.push(
|
|
1877
|
+
for (const [id2, deg] of inDegree.entries()) {
|
|
1878
|
+
if (deg === 0) queue.push(id2);
|
|
1628
1879
|
}
|
|
1629
1880
|
const order = [];
|
|
1630
1881
|
while (queue.length > 0) {
|
|
@@ -1760,7 +2011,7 @@ var KrnlWorkerPool = class {
|
|
|
1760
2011
|
// src/orchestration/canonical/KrnlQ.ts
|
|
1761
2012
|
function generateSecureId(prefix) {
|
|
1762
2013
|
try {
|
|
1763
|
-
return `${prefix}_${(0,
|
|
2014
|
+
return `${prefix}_${(0, import_node_crypto2.randomUUID)()}`;
|
|
1764
2015
|
} catch {
|
|
1765
2016
|
return `${prefix}_${Math.random().toString(36).substring(2, 11)}_${Date.now()}`;
|
|
1766
2017
|
}
|
|
@@ -1828,9 +2079,9 @@ var KrnlQueue = class {
|
|
|
1828
2079
|
if (this.jobs.size <= this.maxRetainedJobs) return;
|
|
1829
2080
|
const excess = this.jobs.size - this.maxRetainedJobs;
|
|
1830
2081
|
let pruned = 0;
|
|
1831
|
-
for (const [
|
|
2082
|
+
for (const [id2, record] of this.jobs.entries()) {
|
|
1832
2083
|
if (record.status === "completed" || record.status === "failed" || record.status === "cancelled") {
|
|
1833
|
-
this.jobs.delete(
|
|
2084
|
+
this.jobs.delete(id2);
|
|
1834
2085
|
pruned++;
|
|
1835
2086
|
if (pruned >= excess) break;
|
|
1836
2087
|
}
|
|
@@ -2444,6 +2695,7 @@ var ServiceFacade = class {
|
|
|
2444
2695
|
defaultFrontend;
|
|
2445
2696
|
instance;
|
|
2446
2697
|
queue;
|
|
2698
|
+
telemetry;
|
|
2447
2699
|
constructor(config) {
|
|
2448
2700
|
if (!config || !config.id || typeof config.id !== "string") {
|
|
2449
2701
|
throw new Error("[ServiceFacade] ServiceFacade requires a valid id.");
|
|
@@ -2473,6 +2725,7 @@ var ServiceFacade = class {
|
|
|
2473
2725
|
operations: {}
|
|
2474
2726
|
});
|
|
2475
2727
|
}
|
|
2728
|
+
this.telemetry = this.instance.telemetry;
|
|
2476
2729
|
this.queue = new KrnlQueue({
|
|
2477
2730
|
queueName: `krnl_queue_${this.id}`,
|
|
2478
2731
|
concurrency: config.concurrency ?? config.queueOptions?.concurrency ?? 10,
|
|
@@ -2516,6 +2769,8 @@ var ServiceFacade = class {
|
|
|
2516
2769
|
*/
|
|
2517
2770
|
async call(op, input, ctx) {
|
|
2518
2771
|
const correlationId = ctx?.correlationId || `corr_${Math.random().toString(36).substring(2, 11)}`;
|
|
2772
|
+
const telemetryParent = typeof ctx?.metadata?.__krnlTelemetryParentSpanId === "string" ? ctx.metadata.__krnlTelemetryParentSpanId : void 0;
|
|
2773
|
+
const telemetryHandle = this.telemetry.begin(op, "service", correlationId, telemetryParent);
|
|
2519
2774
|
const commandId = `cmd_${this.id}_${op}_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`;
|
|
2520
2775
|
const command = {
|
|
2521
2776
|
id: commandId,
|
|
@@ -2525,26 +2780,48 @@ var ServiceFacade = class {
|
|
|
2525
2780
|
idempotencyKey: ctx?.idempotencyKey,
|
|
2526
2781
|
createdAt: Date.now()
|
|
2527
2782
|
};
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2783
|
+
try {
|
|
2784
|
+
const result = await this.queue.executeCommand(command, async (payload, workerCtx) => {
|
|
2785
|
+
WorkerExecutionBoundary.assertWorkerContext(workerCtx);
|
|
2786
|
+
const functionality = this.functionalities[op];
|
|
2787
|
+
if (functionality) {
|
|
2788
|
+
const functionalityTelemetry = this.telemetry.begin(
|
|
2789
|
+
functionality.name,
|
|
2790
|
+
"functionality",
|
|
2791
|
+
workerCtx.correlationId,
|
|
2792
|
+
telemetryHandle.spanId
|
|
2793
|
+
);
|
|
2794
|
+
try {
|
|
2795
|
+
return await functionality.execute(payload, {
|
|
2796
|
+
serviceId: this.id,
|
|
2797
|
+
functionalityId: functionality.id,
|
|
2798
|
+
correlationId: workerCtx.correlationId,
|
|
2799
|
+
state: this.instance.getState()
|
|
2800
|
+
});
|
|
2801
|
+
} catch (error) {
|
|
2802
|
+
functionalityTelemetry.end(error);
|
|
2803
|
+
throw error;
|
|
2804
|
+
} finally {
|
|
2805
|
+
functionalityTelemetry.end();
|
|
2806
|
+
}
|
|
2807
|
+
}
|
|
2808
|
+
return await this.instance.call(op, payload, {
|
|
2535
2809
|
correlationId: workerCtx.correlationId,
|
|
2536
|
-
|
|
2810
|
+
idempotencyKey: command.idempotencyKey,
|
|
2811
|
+
metadata: { __krnlTelemetryInternal: true }
|
|
2537
2812
|
});
|
|
2538
|
-
}
|
|
2539
|
-
return await this.instance.call(op, payload, {
|
|
2540
|
-
correlationId: workerCtx.correlationId,
|
|
2541
|
-
idempotencyKey: command.idempotencyKey
|
|
2542
2813
|
});
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2814
|
+
if (result.status === "FAILED") {
|
|
2815
|
+
const error = new Error(result.error || `[ServiceFacade:${this.id}] Operation '${op}' execution failed.`);
|
|
2816
|
+
telemetryHandle.end(error);
|
|
2817
|
+
throw error;
|
|
2818
|
+
}
|
|
2819
|
+
telemetryHandle.end();
|
|
2820
|
+
return result.data;
|
|
2821
|
+
} catch (error) {
|
|
2822
|
+
telemetryHandle.end(error);
|
|
2823
|
+
throw error;
|
|
2546
2824
|
}
|
|
2547
|
-
return result.data;
|
|
2548
2825
|
}
|
|
2549
2826
|
/**
|
|
2550
2827
|
* External caller callable boundary for functionality orchestration execution.
|
|
@@ -2558,6 +2835,18 @@ var ServiceFacade = class {
|
|
|
2558
2835
|
);
|
|
2559
2836
|
}
|
|
2560
2837
|
const correlationId = options.correlationId || `corr_${Math.random().toString(36).substring(2, 11)}`;
|
|
2838
|
+
const serviceTelemetryHandle = this.telemetry.begin(
|
|
2839
|
+
`orchestrate:${orchestrationName}`,
|
|
2840
|
+
"service",
|
|
2841
|
+
correlationId,
|
|
2842
|
+
typeof options.metadata?.__krnlTelemetryParentSpanId === "string" ? options.metadata.__krnlTelemetryParentSpanId : void 0
|
|
2843
|
+
);
|
|
2844
|
+
const telemetryHandle = this.telemetry.begin(
|
|
2845
|
+
orchestrationName,
|
|
2846
|
+
"orchestration",
|
|
2847
|
+
correlationId,
|
|
2848
|
+
serviceTelemetryHandle.spanId
|
|
2849
|
+
);
|
|
2561
2850
|
const commandId = `cmd_orch_${this.id}_${orchestrationName}_${Date.now()}`;
|
|
2562
2851
|
const command = {
|
|
2563
2852
|
id: commandId,
|
|
@@ -2605,7 +2894,8 @@ var ServiceFacade = class {
|
|
|
2605
2894
|
...s.compensation,
|
|
2606
2895
|
handler: async (compCtx) => {
|
|
2607
2896
|
await this.call(s.compensation.target, compCtx.results[s.id], {
|
|
2608
|
-
correlationId: compCtx.correlationId
|
|
2897
|
+
correlationId: compCtx.correlationId,
|
|
2898
|
+
metadata: { __krnlTelemetryParentSpanId: telemetryHandle.spanId }
|
|
2609
2899
|
});
|
|
2610
2900
|
}
|
|
2611
2901
|
};
|
|
@@ -2621,7 +2911,8 @@ var ServiceFacade = class {
|
|
|
2621
2911
|
stepPayload.input = stepCtx.results.input;
|
|
2622
2912
|
}
|
|
2623
2913
|
return await this.call(s.target, stepPayload, {
|
|
2624
|
-
correlationId: stepCtx.correlationId
|
|
2914
|
+
correlationId: stepCtx.correlationId,
|
|
2915
|
+
metadata: { __krnlTelemetryParentSpanId: telemetryHandle.spanId }
|
|
2625
2916
|
});
|
|
2626
2917
|
}
|
|
2627
2918
|
};
|
|
@@ -2641,7 +2932,8 @@ var ServiceFacade = class {
|
|
|
2641
2932
|
const nestedResult = await this.orchestrate(childOrchId, childInput, {
|
|
2642
2933
|
correlationId: childCtx.correlationId,
|
|
2643
2934
|
timeoutMs: childOrch.timeoutMs,
|
|
2644
|
-
abortSignal: options.abortSignal
|
|
2935
|
+
abortSignal: options.abortSignal,
|
|
2936
|
+
metadata: { __krnlTelemetryParentSpanId: telemetryHandle.spanId }
|
|
2645
2937
|
});
|
|
2646
2938
|
if (nestedResult.status !== "COMPLETED") {
|
|
2647
2939
|
throw new Error(nestedResult.error || `Nested orchestration "${childOrchId}" failed.`);
|
|
@@ -2689,8 +2981,13 @@ var ServiceFacade = class {
|
|
|
2689
2981
|
});
|
|
2690
2982
|
}
|
|
2691
2983
|
if (cmdResult.status === "FAILED" || orchestrationResult?.status === "FAILED") {
|
|
2692
|
-
|
|
2984
|
+
const error = new Error(orchestrationResult?.error || cmdResult.error || `[ServiceFacade:${this.id}] Orchestration failed.`);
|
|
2985
|
+
telemetryHandle.end(error);
|
|
2986
|
+
serviceTelemetryHandle.end(error);
|
|
2987
|
+
throw error;
|
|
2693
2988
|
}
|
|
2989
|
+
telemetryHandle.end();
|
|
2990
|
+
serviceTelemetryHandle.end();
|
|
2694
2991
|
return cmdResult.data;
|
|
2695
2992
|
}
|
|
2696
2993
|
/**
|
|
@@ -3349,9 +3646,9 @@ var ServiceRuntime = class {
|
|
|
3349
3646
|
// src/discovery/ServiceDiscovery.ts
|
|
3350
3647
|
var ServiceDiscovery = class {
|
|
3351
3648
|
peers = /* @__PURE__ */ new Map();
|
|
3352
|
-
registerPeer(
|
|
3353
|
-
this.peers.set(
|
|
3354
|
-
id,
|
|
3649
|
+
registerPeer(id2, name, endpoints) {
|
|
3650
|
+
this.peers.set(id2, {
|
|
3651
|
+
id: id2,
|
|
3355
3652
|
name,
|
|
3356
3653
|
endpoints,
|
|
3357
3654
|
lastSeen: Date.now()
|
|
@@ -3360,8 +3657,8 @@ var ServiceDiscovery = class {
|
|
|
3360
3657
|
getPeers() {
|
|
3361
3658
|
return Array.from(this.peers.values());
|
|
3362
3659
|
}
|
|
3363
|
-
findPeer(
|
|
3364
|
-
return this.peers.get(
|
|
3660
|
+
findPeer(id2) {
|
|
3661
|
+
return this.peers.get(id2);
|
|
3365
3662
|
}
|
|
3366
3663
|
};
|
|
3367
3664
|
|
|
@@ -3837,6 +4134,7 @@ var gutts = __toESM(require("@dinilmusick/gutts"), 1);
|
|
|
3837
4134
|
ServiceRegistry,
|
|
3838
4135
|
ServiceRuntime,
|
|
3839
4136
|
ServiceStateStore,
|
|
4137
|
+
TelemetryController,
|
|
3840
4138
|
UdpProtocolAdapter,
|
|
3841
4139
|
WebSocketProtocolAdapter,
|
|
3842
4140
|
WorkerExecutionBoundary,
|
|
@@ -3845,7 +4143,10 @@ var gutts = __toESM(require("@dinilmusick/gutts"), 1);
|
|
|
3845
4143
|
createServiceDefinition,
|
|
3846
4144
|
createServiceFacade,
|
|
3847
4145
|
createServiceProxy,
|
|
4146
|
+
deltaResources,
|
|
3848
4147
|
gutts,
|
|
4148
|
+
sampleResources,
|
|
4149
|
+
telemetryNow,
|
|
3849
4150
|
validateOrchestrationDAG,
|
|
3850
4151
|
validateServiceDefinition
|
|
3851
4152
|
});
|