@ultrst-armada/krnl 1.0.8 → 1.0.10
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 +382 -57
- package/packages/core/dist/index.d.cts +191 -1
- package/packages/core/dist/index.d.ts +191 -1
- package/packages/core/dist/index.js +377 -57
- package/packages/core/package.json +1 -1
|
@@ -62,6 +62,227 @@ var LifecycleManager = class {
|
|
|
62
62
|
}
|
|
63
63
|
};
|
|
64
64
|
|
|
65
|
+
// src/telemetry/TelemetryController.ts
|
|
66
|
+
import { randomUUID } from "crypto";
|
|
67
|
+
|
|
68
|
+
// src/telemetry/TelemetryResources.ts
|
|
69
|
+
var runtimeProcess = typeof globalThis !== "undefined" ? globalThis.process : void 0;
|
|
70
|
+
var runtimePerformance = typeof globalThis !== "undefined" ? globalThis.performance : void 0;
|
|
71
|
+
function telemetryNow() {
|
|
72
|
+
return runtimePerformance?.now ? runtimePerformance.now() : Date.now();
|
|
73
|
+
}
|
|
74
|
+
function sampleResources() {
|
|
75
|
+
const memory = runtimeProcess?.memoryUsage?.();
|
|
76
|
+
const cpu = runtimeProcess?.cpuUsage?.();
|
|
77
|
+
const eventLoop = runtimePerformance?.eventLoopUtilization?.();
|
|
78
|
+
return {
|
|
79
|
+
cpuUserMicros: cpu?.user,
|
|
80
|
+
cpuSystemMicros: cpu?.system,
|
|
81
|
+
heapUsedBytes: memory?.heapUsed,
|
|
82
|
+
heapTotalBytes: memory?.heapTotal,
|
|
83
|
+
rssBytes: memory?.rss,
|
|
84
|
+
externalBytes: memory?.external,
|
|
85
|
+
arrayBuffersBytes: memory?.arrayBuffers,
|
|
86
|
+
eventLoopUtilization: eventLoop?.utilization,
|
|
87
|
+
scope: memory || cpu || eventLoop ? "process" : "runtime"
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function deltaResources(start, end) {
|
|
91
|
+
const delta = (a, b) => a === void 0 || b === void 0 ? void 0 : b - a;
|
|
92
|
+
return {
|
|
93
|
+
cpuUserMicros: delta(start.cpuUserMicros, end.cpuUserMicros),
|
|
94
|
+
cpuSystemMicros: delta(start.cpuSystemMicros, end.cpuSystemMicros),
|
|
95
|
+
heapUsedBytes: delta(start.heapUsedBytes, end.heapUsedBytes),
|
|
96
|
+
heapTotalBytes: delta(start.heapTotalBytes, end.heapTotalBytes),
|
|
97
|
+
rssBytes: delta(start.rssBytes, end.rssBytes),
|
|
98
|
+
externalBytes: delta(start.externalBytes, end.externalBytes),
|
|
99
|
+
arrayBuffersBytes: delta(start.arrayBuffersBytes, end.arrayBuffersBytes),
|
|
100
|
+
eventLoopUtilization: delta(start.eventLoopUtilization, end.eventLoopUtilization),
|
|
101
|
+
scope: start.scope
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// src/telemetry/TelemetryController.ts
|
|
106
|
+
var id = (prefix) => `${prefix}_${randomUUID()}`;
|
|
107
|
+
function percentiles(values) {
|
|
108
|
+
if (!values.length) return { min: 0, mean: 0, p50: 0, p90: 0, p95: 0, p99: 0, max: 0 };
|
|
109
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
110
|
+
const pick = (p) => sorted[Math.min(sorted.length - 1, Math.floor((sorted.length - 1) * p))];
|
|
111
|
+
return {
|
|
112
|
+
min: sorted[0],
|
|
113
|
+
mean: sorted.reduce((sum, value) => sum + value, 0) / sorted.length,
|
|
114
|
+
p50: pick(0.5),
|
|
115
|
+
p90: pick(0.9),
|
|
116
|
+
p95: pick(0.95),
|
|
117
|
+
p99: pick(0.99),
|
|
118
|
+
max: sorted[sorted.length - 1]
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
var TelemetryController = class {
|
|
122
|
+
constructor(serviceId, options = {}) {
|
|
123
|
+
this.serviceId = serviceId;
|
|
124
|
+
this.mode = options.mode ?? "off";
|
|
125
|
+
this.maxSamples = Math.max(1, options.maxSamples ?? 2048);
|
|
126
|
+
this.maxRecentInvocations = Math.max(1, options.maxRecentInvocations ?? 100);
|
|
127
|
+
}
|
|
128
|
+
serviceId;
|
|
129
|
+
mode;
|
|
130
|
+
maxSamples;
|
|
131
|
+
maxRecentInvocations;
|
|
132
|
+
samples = [];
|
|
133
|
+
active = /* @__PURE__ */ new Map();
|
|
134
|
+
totalInvocationCount = 0;
|
|
135
|
+
totalSuccessCount = 0;
|
|
136
|
+
totalErrorCount = 0;
|
|
137
|
+
lastInvocationAt;
|
|
138
|
+
enable(mode = "standard") {
|
|
139
|
+
this.mode = mode;
|
|
140
|
+
}
|
|
141
|
+
disable() {
|
|
142
|
+
this.mode = "off";
|
|
143
|
+
this.active.clear();
|
|
144
|
+
}
|
|
145
|
+
setMode(mode) {
|
|
146
|
+
this.mode = mode;
|
|
147
|
+
if (mode === "off") this.active.clear();
|
|
148
|
+
}
|
|
149
|
+
getMode() {
|
|
150
|
+
return this.mode;
|
|
151
|
+
}
|
|
152
|
+
status() {
|
|
153
|
+
return {
|
|
154
|
+
enabled: this.mode !== "off",
|
|
155
|
+
mode: this.mode,
|
|
156
|
+
serviceId: this.serviceId,
|
|
157
|
+
invocationCount: this.totalInvocationCount,
|
|
158
|
+
activeInvocations: this.active.size,
|
|
159
|
+
lastInvocationAt: this.lastInvocationAt
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
begin(target, kind, correlationId, parentSpanId) {
|
|
163
|
+
if (this.mode === "off") {
|
|
164
|
+
return {
|
|
165
|
+
invocationId: "",
|
|
166
|
+
traceId: "",
|
|
167
|
+
spanId: "",
|
|
168
|
+
parentSpanId,
|
|
169
|
+
end: () => void 0
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
const invocationId = id("inv");
|
|
173
|
+
const spanId = id("span");
|
|
174
|
+
const traceId = parentSpanId ? this.findTraceId(parentSpanId) ?? id("trace") : id("trace");
|
|
175
|
+
const active = {
|
|
176
|
+
invocationId,
|
|
177
|
+
traceId,
|
|
178
|
+
spanId,
|
|
179
|
+
parentSpanId,
|
|
180
|
+
serviceId: this.serviceId,
|
|
181
|
+
target,
|
|
182
|
+
kind,
|
|
183
|
+
correlationId,
|
|
184
|
+
startedAt: telemetryNow(),
|
|
185
|
+
resourcesStart: this.mode === "standard" ? void 0 : sampleResources()
|
|
186
|
+
};
|
|
187
|
+
this.active.set(invocationId, active);
|
|
188
|
+
return {
|
|
189
|
+
invocationId,
|
|
190
|
+
traceId,
|
|
191
|
+
spanId,
|
|
192
|
+
parentSpanId,
|
|
193
|
+
end: (error) => this.finish(active, error)
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
reset() {
|
|
197
|
+
this.samples.length = 0;
|
|
198
|
+
this.active.clear();
|
|
199
|
+
this.totalInvocationCount = 0;
|
|
200
|
+
this.totalSuccessCount = 0;
|
|
201
|
+
this.totalErrorCount = 0;
|
|
202
|
+
this.lastInvocationAt = void 0;
|
|
203
|
+
}
|
|
204
|
+
snapshot() {
|
|
205
|
+
const invocations = this.samples.slice();
|
|
206
|
+
const durations = invocations.map((item) => item.durationMs);
|
|
207
|
+
const targetMap = /* @__PURE__ */ new Map();
|
|
208
|
+
for (const invocation of invocations) {
|
|
209
|
+
const key = `${invocation.kind}:${invocation.target}`;
|
|
210
|
+
const group = targetMap.get(key) ?? [];
|
|
211
|
+
group.push(invocation);
|
|
212
|
+
targetMap.set(key, group);
|
|
213
|
+
}
|
|
214
|
+
const targets = [...targetMap.values()].map((group) => ({
|
|
215
|
+
target: group[0].target,
|
|
216
|
+
kind: group[0].kind,
|
|
217
|
+
count: group.length,
|
|
218
|
+
successCount: group.filter((item) => item.status === "completed").length,
|
|
219
|
+
errorCount: group.filter((item) => item.status === "failed").length,
|
|
220
|
+
durationMs: percentiles(group.map((item) => item.durationMs)),
|
|
221
|
+
lastInvocationAt: group[group.length - 1]?.completedAt
|
|
222
|
+
}));
|
|
223
|
+
return {
|
|
224
|
+
serviceId: this.serviceId,
|
|
225
|
+
mode: this.mode,
|
|
226
|
+
capturedAt: Date.now(),
|
|
227
|
+
status: this.status(),
|
|
228
|
+
totals: {
|
|
229
|
+
invocationCount: this.totalInvocationCount,
|
|
230
|
+
successCount: this.totalSuccessCount,
|
|
231
|
+
errorCount: this.totalErrorCount,
|
|
232
|
+
durationMs: percentiles(durations)
|
|
233
|
+
},
|
|
234
|
+
targets,
|
|
235
|
+
activeInvocations: this.active.size,
|
|
236
|
+
recentInvocations: invocations.slice(-this.maxRecentInvocations)
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
functionality(name) {
|
|
240
|
+
return this.snapshot().targets.find((target) => target.kind === "functionality" && target.target === name);
|
|
241
|
+
}
|
|
242
|
+
functionalities() {
|
|
243
|
+
return this.snapshot().targets.filter((target) => target.kind === "functionality");
|
|
244
|
+
}
|
|
245
|
+
findTraceId(parentSpanId) {
|
|
246
|
+
for (let index = this.samples.length - 1; index >= 0; index -= 1) {
|
|
247
|
+
if (this.samples[index].spanId === parentSpanId) return this.samples[index].traceId;
|
|
248
|
+
}
|
|
249
|
+
for (const active of this.active.values()) {
|
|
250
|
+
if (active.spanId === parentSpanId) return active.traceId;
|
|
251
|
+
}
|
|
252
|
+
return void 0;
|
|
253
|
+
}
|
|
254
|
+
finish(active, error) {
|
|
255
|
+
if (!this.active.delete(active.invocationId)) return;
|
|
256
|
+
const completedAt = telemetryNow();
|
|
257
|
+
const resourcesEnd = this.mode === "standard" ? void 0 : sampleResources();
|
|
258
|
+
const invocation = {
|
|
259
|
+
invocationId: active.invocationId,
|
|
260
|
+
traceId: active.traceId,
|
|
261
|
+
spanId: active.spanId,
|
|
262
|
+
parentSpanId: active.parentSpanId,
|
|
263
|
+
serviceId: active.serviceId,
|
|
264
|
+
target: active.target,
|
|
265
|
+
kind: active.kind,
|
|
266
|
+
correlationId: active.correlationId,
|
|
267
|
+
startedAt: active.startedAt,
|
|
268
|
+
completedAt,
|
|
269
|
+
durationMs: Math.max(0, completedAt - active.startedAt),
|
|
270
|
+
status: error === void 0 ? "completed" : "failed",
|
|
271
|
+
error: error === void 0 ? void 0 : {
|
|
272
|
+
name: error instanceof Error ? error.name : "Error",
|
|
273
|
+
message: error instanceof Error ? error.message : String(error)
|
|
274
|
+
},
|
|
275
|
+
resources: active.resourcesStart && resourcesEnd ? { start: active.resourcesStart, end: resourcesEnd, delta: deltaResources(active.resourcesStart, resourcesEnd) } : void 0
|
|
276
|
+
};
|
|
277
|
+
this.samples.push(invocation);
|
|
278
|
+
this.totalInvocationCount += 1;
|
|
279
|
+
if (invocation.status === "completed") this.totalSuccessCount += 1;
|
|
280
|
+
else this.totalErrorCount += 1;
|
|
281
|
+
if (this.samples.length > this.maxSamples) this.samples.splice(0, this.samples.length - this.maxSamples);
|
|
282
|
+
this.lastInvocationAt = Date.now();
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
|
|
65
286
|
// src/services/ServiceInstance.ts
|
|
66
287
|
var ServiceInstance = class {
|
|
67
288
|
constructor(definition) {
|
|
@@ -69,6 +290,7 @@ var ServiceInstance = class {
|
|
|
69
290
|
this.id = definition.id;
|
|
70
291
|
this.name = definition.name;
|
|
71
292
|
this.version = definition.version;
|
|
293
|
+
this.telemetry = new TelemetryController(this.id);
|
|
72
294
|
this.lifecycle = new LifecycleManager();
|
|
73
295
|
if (definition.state) {
|
|
74
296
|
this.stateStore = new ServiceStateStore(definition.state.initial);
|
|
@@ -78,6 +300,7 @@ var ServiceInstance = class {
|
|
|
78
300
|
id;
|
|
79
301
|
name;
|
|
80
302
|
version;
|
|
303
|
+
telemetry;
|
|
81
304
|
stateStore;
|
|
82
305
|
lifecycle;
|
|
83
306
|
initialized = false;
|
|
@@ -142,7 +365,19 @@ var ServiceInstance = class {
|
|
|
142
365
|
if (!operation) {
|
|
143
366
|
throw new Error("[Service:" + this.name + "] Operation '" + op + "' not found.");
|
|
144
367
|
}
|
|
145
|
-
|
|
368
|
+
if (ctx.metadata?.__krnlTelemetryInternal === true) {
|
|
369
|
+
return await operation.handler(input, ctx);
|
|
370
|
+
}
|
|
371
|
+
const parentSpanId = typeof ctx.metadata?.__krnlTelemetryParentSpanId === "string" ? ctx.metadata.__krnlTelemetryParentSpanId : void 0;
|
|
372
|
+
const handle = this.telemetry.begin(op, "service", ctx.correlationId, parentSpanId);
|
|
373
|
+
try {
|
|
374
|
+
const output = await operation.handler(input, ctx);
|
|
375
|
+
handle.end();
|
|
376
|
+
return output;
|
|
377
|
+
} catch (error) {
|
|
378
|
+
handle.end(error);
|
|
379
|
+
throw error;
|
|
380
|
+
}
|
|
146
381
|
}
|
|
147
382
|
getState() {
|
|
148
383
|
return this.stateStore?.getState() ?? Object.freeze({});
|
|
@@ -174,6 +409,7 @@ var ServiceProxy = class {
|
|
|
174
409
|
this.id = definition.id;
|
|
175
410
|
this.name = definition.name;
|
|
176
411
|
this.version = definition.version;
|
|
412
|
+
this.telemetry = new TelemetryController(this.id);
|
|
177
413
|
this.stateCache = { ...definition.state?.initial ?? {} };
|
|
178
414
|
}
|
|
179
415
|
definition;
|
|
@@ -182,6 +418,7 @@ var ServiceProxy = class {
|
|
|
182
418
|
id;
|
|
183
419
|
name;
|
|
184
420
|
version;
|
|
421
|
+
telemetry;
|
|
185
422
|
stateCache;
|
|
186
423
|
eventHandlers = /* @__PURE__ */ new Map();
|
|
187
424
|
lifecycle = new LifecycleManager();
|
|
@@ -239,11 +476,21 @@ var ServiceProxy = class {
|
|
|
239
476
|
payload: input,
|
|
240
477
|
timestamp: Date.now()
|
|
241
478
|
};
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
|
|
479
|
+
const parentSpanId = typeof ctx.metadata?.__krnlTelemetryParentSpanId === "string" ? ctx.metadata.__krnlTelemetryParentSpanId : void 0;
|
|
480
|
+
const handle = this.telemetry.begin(op, "service", ctx.correlationId, parentSpanId);
|
|
481
|
+
try {
|
|
482
|
+
const response = await this.adapter.send(this.endpoint, envelope);
|
|
483
|
+
if (response.error) {
|
|
484
|
+
const error = new Error("[ServiceProxy:" + this.name + "] Remote error: " + response.error);
|
|
485
|
+
handle.end(error);
|
|
486
|
+
throw error;
|
|
487
|
+
}
|
|
488
|
+
handle.end();
|
|
489
|
+
return response.payload;
|
|
490
|
+
} catch (error) {
|
|
491
|
+
handle.end(error);
|
|
492
|
+
throw error;
|
|
245
493
|
}
|
|
246
|
-
return response.payload;
|
|
247
494
|
}
|
|
248
495
|
getState() {
|
|
249
496
|
return Object.freeze({ ...this.stateCache });
|
|
@@ -391,22 +638,22 @@ var FunctionalityFacade = class {
|
|
|
391
638
|
definition;
|
|
392
639
|
eventBus;
|
|
393
640
|
events;
|
|
394
|
-
constructor(
|
|
395
|
-
if (!
|
|
641
|
+
constructor(id2, definition, options = {}) {
|
|
642
|
+
if (!id2 || typeof id2 !== "string") {
|
|
396
643
|
throw new Error("[FunctionalityFacade] Functionality id must be a non-empty string.");
|
|
397
644
|
}
|
|
398
645
|
if (!definition || typeof definition.execute !== "function") {
|
|
399
|
-
throw new Error(`[FunctionalityFacade:${
|
|
646
|
+
throw new Error(`[FunctionalityFacade:${id2}] Functionality must define execute().`);
|
|
400
647
|
}
|
|
401
|
-
this.id =
|
|
402
|
-
this.name = definition.name ||
|
|
648
|
+
this.id = id2;
|
|
649
|
+
this.name = definition.name || id2;
|
|
403
650
|
this.description = definition.description || "";
|
|
404
651
|
this.bubbleEvents = options.bubbleEvents ?? definition.bubbleEvents ?? true;
|
|
405
652
|
this.definition = definition;
|
|
406
653
|
this.eventBus = new EventBus();
|
|
407
654
|
for (const reserved of ["triggered", "completed", "failed"]) {
|
|
408
655
|
if (definition.events && reserved in definition.events) {
|
|
409
|
-
throw new Error(`[FunctionalityFacade:${
|
|
656
|
+
throw new Error(`[FunctionalityFacade:${id2}] Event '${reserved}' is reserved for functionality lifecycle.`);
|
|
410
657
|
}
|
|
411
658
|
}
|
|
412
659
|
const eventNames = [
|
|
@@ -520,11 +767,11 @@ var PriorityQueue = class {
|
|
|
520
767
|
return item.run;
|
|
521
768
|
}
|
|
522
769
|
enqueue(run, options) {
|
|
523
|
-
const { priority = 0, id } = options ?? {};
|
|
770
|
+
const { priority = 0, id: id2 } = options ?? {};
|
|
524
771
|
const { size } = this;
|
|
525
772
|
const element = {
|
|
526
773
|
priority,
|
|
527
|
-
id,
|
|
774
|
+
id: id2,
|
|
528
775
|
run
|
|
529
776
|
};
|
|
530
777
|
if (size === 0) {
|
|
@@ -541,16 +788,16 @@ var PriorityQueue = class {
|
|
|
541
788
|
const index = lowerBound(this.#queue, element, (a, b) => a.priority === b.priority ? 0 : b.priority - a.priority);
|
|
542
789
|
this.#queue.splice(index, 0, element);
|
|
543
790
|
}
|
|
544
|
-
setPriority(
|
|
545
|
-
const index = this.#findIndex((element) => element.id ===
|
|
791
|
+
setPriority(id2, priority) {
|
|
792
|
+
const index = this.#findIndex((element) => element.id === id2);
|
|
546
793
|
if (index === -1) {
|
|
547
|
-
throw new ReferenceError(`No promise function with the id "${
|
|
794
|
+
throw new ReferenceError(`No promise function with the id "${id2}" exists in the queue.`);
|
|
548
795
|
}
|
|
549
796
|
if (this.#queue[index].priority === priority) {
|
|
550
797
|
return;
|
|
551
798
|
}
|
|
552
799
|
const [item] = this.#queue.splice(index, 1);
|
|
553
|
-
this.enqueue(item.run, { priority, id });
|
|
800
|
+
this.enqueue(item.run, { priority, id: id2 });
|
|
554
801
|
}
|
|
555
802
|
remove(idOrRun) {
|
|
556
803
|
const index = this.#findIndex((element) => (typeof idOrRun === "string" ? element.id : element.run) === idOrRun);
|
|
@@ -966,17 +1213,17 @@ var PQueue = class extends EventTarget {
|
|
|
966
1213
|
}
|
|
967
1214
|
}
|
|
968
1215
|
async #add(function_, options, waitingTask) {
|
|
969
|
-
const
|
|
1216
|
+
const id2 = options.id ?? (this.#idAssigner++).toString();
|
|
970
1217
|
options = {
|
|
971
1218
|
timeout: this.#timeout,
|
|
972
1219
|
...options,
|
|
973
|
-
id
|
|
1220
|
+
id: id2
|
|
974
1221
|
};
|
|
975
1222
|
validateTimeout(options.timeout);
|
|
976
1223
|
if (options.priority !== void 0 && (typeof options.priority !== "number" || Number.isNaN(options.priority))) {
|
|
977
1224
|
throw new TypeError(`Expected \`priority\` to be a number, got \`${String(options.priority)}\` (${typeof options.priority})`);
|
|
978
1225
|
}
|
|
979
|
-
waitingTask.id =
|
|
1226
|
+
waitingTask.id = id2;
|
|
980
1227
|
waitingTask.priority = options.priority ?? 0;
|
|
981
1228
|
return new Promise((resolve, reject) => {
|
|
982
1229
|
if (options.signal?.aborted) {
|
|
@@ -993,7 +1240,7 @@ var PQueue = class extends EventTarget {
|
|
|
993
1240
|
}
|
|
994
1241
|
this.#pending++;
|
|
995
1242
|
const runningTask = {
|
|
996
|
-
id,
|
|
1243
|
+
id: id2,
|
|
997
1244
|
priority: waitingTask.priority,
|
|
998
1245
|
startTime: Date.now(),
|
|
999
1246
|
timeout: options.timeout
|
|
@@ -1060,7 +1307,7 @@ var PQueue = class extends EventTarget {
|
|
|
1060
1307
|
if (this.#queue instanceof PriorityQueue) {
|
|
1061
1308
|
this.#queue.remove(run);
|
|
1062
1309
|
} else {
|
|
1063
|
-
this.#queue.remove(
|
|
1310
|
+
this.#queue.remove(id2);
|
|
1064
1311
|
}
|
|
1065
1312
|
reject(signal.reason);
|
|
1066
1313
|
this.#processQueue();
|
|
@@ -1136,18 +1383,18 @@ var PQueue = class extends EventTarget {
|
|
|
1136
1383
|
// '🦀' runs last
|
|
1137
1384
|
```
|
|
1138
1385
|
*/
|
|
1139
|
-
setPriority(
|
|
1386
|
+
setPriority(id2, priority) {
|
|
1140
1387
|
if (typeof priority !== "number" || !Number.isFinite(priority)) {
|
|
1141
1388
|
throw new TypeError(`Expected \`priority\` to be a finite number, got \`${priority}\` (${typeof priority})`);
|
|
1142
1389
|
}
|
|
1143
1390
|
for (const waitingTask of this.#waitingTasks) {
|
|
1144
|
-
if (waitingTask.id ===
|
|
1145
|
-
this.#queue.setPriority(
|
|
1391
|
+
if (waitingTask.id === id2) {
|
|
1392
|
+
this.#queue.setPriority(id2, priority);
|
|
1146
1393
|
waitingTask.priority = priority;
|
|
1147
1394
|
return;
|
|
1148
1395
|
}
|
|
1149
1396
|
}
|
|
1150
|
-
throw new ReferenceError(`No promise function with the id "${
|
|
1397
|
+
throw new ReferenceError(`No promise function with the id "${id2}" exists in the queue.`);
|
|
1151
1398
|
}
|
|
1152
1399
|
/**
|
|
1153
1400
|
Adds a sync or async task to the queue.
|
|
@@ -1490,7 +1737,7 @@ var TimeoutError = class extends DOMException {
|
|
|
1490
1737
|
};
|
|
1491
1738
|
|
|
1492
1739
|
// src/orchestration/canonical/KrnlQ.ts
|
|
1493
|
-
import { randomUUID } from "crypto";
|
|
1740
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
1494
1741
|
|
|
1495
1742
|
// src/orchestration/canonical/model.ts
|
|
1496
1743
|
function validateOrchestrationDAG(steps) {
|
|
@@ -1557,8 +1804,8 @@ function validateOrchestrationDAG(steps) {
|
|
|
1557
1804
|
}
|
|
1558
1805
|
}
|
|
1559
1806
|
const queue = [];
|
|
1560
|
-
for (const [
|
|
1561
|
-
if (deg === 0) queue.push(
|
|
1807
|
+
for (const [id2, deg] of inDegree.entries()) {
|
|
1808
|
+
if (deg === 0) queue.push(id2);
|
|
1562
1809
|
}
|
|
1563
1810
|
const order = [];
|
|
1564
1811
|
while (queue.length > 0) {
|
|
@@ -1694,7 +1941,7 @@ var KrnlWorkerPool = class {
|
|
|
1694
1941
|
// src/orchestration/canonical/KrnlQ.ts
|
|
1695
1942
|
function generateSecureId(prefix) {
|
|
1696
1943
|
try {
|
|
1697
|
-
return `${prefix}_${
|
|
1944
|
+
return `${prefix}_${randomUUID2()}`;
|
|
1698
1945
|
} catch {
|
|
1699
1946
|
return `${prefix}_${Math.random().toString(36).substring(2, 11)}_${Date.now()}`;
|
|
1700
1947
|
}
|
|
@@ -1762,9 +2009,9 @@ var KrnlQueue = class {
|
|
|
1762
2009
|
if (this.jobs.size <= this.maxRetainedJobs) return;
|
|
1763
2010
|
const excess = this.jobs.size - this.maxRetainedJobs;
|
|
1764
2011
|
let pruned = 0;
|
|
1765
|
-
for (const [
|
|
2012
|
+
for (const [id2, record] of this.jobs.entries()) {
|
|
1766
2013
|
if (record.status === "completed" || record.status === "failed" || record.status === "cancelled") {
|
|
1767
|
-
this.jobs.delete(
|
|
2014
|
+
this.jobs.delete(id2);
|
|
1768
2015
|
pruned++;
|
|
1769
2016
|
if (pruned >= excess) break;
|
|
1770
2017
|
}
|
|
@@ -2378,6 +2625,7 @@ var ServiceFacade = class {
|
|
|
2378
2625
|
defaultFrontend;
|
|
2379
2626
|
instance;
|
|
2380
2627
|
queue;
|
|
2628
|
+
telemetry;
|
|
2381
2629
|
constructor(config) {
|
|
2382
2630
|
if (!config || !config.id || typeof config.id !== "string") {
|
|
2383
2631
|
throw new Error("[ServiceFacade] ServiceFacade requires a valid id.");
|
|
@@ -2407,6 +2655,7 @@ var ServiceFacade = class {
|
|
|
2407
2655
|
operations: {}
|
|
2408
2656
|
});
|
|
2409
2657
|
}
|
|
2658
|
+
this.telemetry = this.instance.telemetry;
|
|
2410
2659
|
this.queue = new KrnlQueue({
|
|
2411
2660
|
queueName: `krnl_queue_${this.id}`,
|
|
2412
2661
|
concurrency: config.concurrency ?? config.queueOptions?.concurrency ?? 10,
|
|
@@ -2450,6 +2699,8 @@ var ServiceFacade = class {
|
|
|
2450
2699
|
*/
|
|
2451
2700
|
async call(op, input, ctx) {
|
|
2452
2701
|
const correlationId = ctx?.correlationId || `corr_${Math.random().toString(36).substring(2, 11)}`;
|
|
2702
|
+
const telemetryParent = typeof ctx?.metadata?.__krnlTelemetryParentSpanId === "string" ? ctx.metadata.__krnlTelemetryParentSpanId : void 0;
|
|
2703
|
+
const telemetryHandle = this.telemetry.begin(op, "service", correlationId, telemetryParent);
|
|
2453
2704
|
const commandId = `cmd_${this.id}_${op}_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`;
|
|
2454
2705
|
const command = {
|
|
2455
2706
|
id: commandId,
|
|
@@ -2459,26 +2710,48 @@ var ServiceFacade = class {
|
|
|
2459
2710
|
idempotencyKey: ctx?.idempotencyKey,
|
|
2460
2711
|
createdAt: Date.now()
|
|
2461
2712
|
};
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2713
|
+
try {
|
|
2714
|
+
const result = await this.queue.executeCommand(command, async (payload, workerCtx) => {
|
|
2715
|
+
WorkerExecutionBoundary.assertWorkerContext(workerCtx);
|
|
2716
|
+
const functionality = this.functionalities[op];
|
|
2717
|
+
if (functionality) {
|
|
2718
|
+
const functionalityTelemetry = this.telemetry.begin(
|
|
2719
|
+
functionality.name,
|
|
2720
|
+
"functionality",
|
|
2721
|
+
workerCtx.correlationId,
|
|
2722
|
+
telemetryHandle.spanId
|
|
2723
|
+
);
|
|
2724
|
+
try {
|
|
2725
|
+
return await functionality.execute(payload, {
|
|
2726
|
+
serviceId: this.id,
|
|
2727
|
+
functionalityId: functionality.id,
|
|
2728
|
+
correlationId: workerCtx.correlationId,
|
|
2729
|
+
state: this.instance.getState()
|
|
2730
|
+
});
|
|
2731
|
+
} catch (error) {
|
|
2732
|
+
functionalityTelemetry.end(error);
|
|
2733
|
+
throw error;
|
|
2734
|
+
} finally {
|
|
2735
|
+
functionalityTelemetry.end();
|
|
2736
|
+
}
|
|
2737
|
+
}
|
|
2738
|
+
return await this.instance.call(op, payload, {
|
|
2469
2739
|
correlationId: workerCtx.correlationId,
|
|
2470
|
-
|
|
2740
|
+
idempotencyKey: command.idempotencyKey,
|
|
2741
|
+
metadata: { __krnlTelemetryInternal: true }
|
|
2471
2742
|
});
|
|
2472
|
-
}
|
|
2473
|
-
return await this.instance.call(op, payload, {
|
|
2474
|
-
correlationId: workerCtx.correlationId,
|
|
2475
|
-
idempotencyKey: command.idempotencyKey
|
|
2476
2743
|
});
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2744
|
+
if (result.status === "FAILED") {
|
|
2745
|
+
const error = new Error(result.error || `[ServiceFacade:${this.id}] Operation '${op}' execution failed.`);
|
|
2746
|
+
telemetryHandle.end(error);
|
|
2747
|
+
throw error;
|
|
2748
|
+
}
|
|
2749
|
+
telemetryHandle.end();
|
|
2750
|
+
return result.data;
|
|
2751
|
+
} catch (error) {
|
|
2752
|
+
telemetryHandle.end(error);
|
|
2753
|
+
throw error;
|
|
2480
2754
|
}
|
|
2481
|
-
return result.data;
|
|
2482
2755
|
}
|
|
2483
2756
|
/**
|
|
2484
2757
|
* External caller callable boundary for functionality orchestration execution.
|
|
@@ -2492,6 +2765,18 @@ var ServiceFacade = class {
|
|
|
2492
2765
|
);
|
|
2493
2766
|
}
|
|
2494
2767
|
const correlationId = options.correlationId || `corr_${Math.random().toString(36).substring(2, 11)}`;
|
|
2768
|
+
const serviceTelemetryHandle = this.telemetry.begin(
|
|
2769
|
+
`orchestrate:${orchestrationName}`,
|
|
2770
|
+
"service",
|
|
2771
|
+
correlationId,
|
|
2772
|
+
typeof options.metadata?.__krnlTelemetryParentSpanId === "string" ? options.metadata.__krnlTelemetryParentSpanId : void 0
|
|
2773
|
+
);
|
|
2774
|
+
const telemetryHandle = this.telemetry.begin(
|
|
2775
|
+
orchestrationName,
|
|
2776
|
+
"orchestration",
|
|
2777
|
+
correlationId,
|
|
2778
|
+
serviceTelemetryHandle.spanId
|
|
2779
|
+
);
|
|
2495
2780
|
const commandId = `cmd_orch_${this.id}_${orchestrationName}_${Date.now()}`;
|
|
2496
2781
|
const command = {
|
|
2497
2782
|
id: commandId,
|
|
@@ -2539,7 +2824,8 @@ var ServiceFacade = class {
|
|
|
2539
2824
|
...s.compensation,
|
|
2540
2825
|
handler: async (compCtx) => {
|
|
2541
2826
|
await this.call(s.compensation.target, compCtx.results[s.id], {
|
|
2542
|
-
correlationId: compCtx.correlationId
|
|
2827
|
+
correlationId: compCtx.correlationId,
|
|
2828
|
+
metadata: { __krnlTelemetryParentSpanId: telemetryHandle.spanId }
|
|
2543
2829
|
});
|
|
2544
2830
|
}
|
|
2545
2831
|
};
|
|
@@ -2555,7 +2841,8 @@ var ServiceFacade = class {
|
|
|
2555
2841
|
stepPayload.input = stepCtx.results.input;
|
|
2556
2842
|
}
|
|
2557
2843
|
return await this.call(s.target, stepPayload, {
|
|
2558
|
-
correlationId: stepCtx.correlationId
|
|
2844
|
+
correlationId: stepCtx.correlationId,
|
|
2845
|
+
metadata: { __krnlTelemetryParentSpanId: telemetryHandle.spanId }
|
|
2559
2846
|
});
|
|
2560
2847
|
}
|
|
2561
2848
|
};
|
|
@@ -2575,7 +2862,8 @@ var ServiceFacade = class {
|
|
|
2575
2862
|
const nestedResult = await this.orchestrate(childOrchId, childInput, {
|
|
2576
2863
|
correlationId: childCtx.correlationId,
|
|
2577
2864
|
timeoutMs: childOrch.timeoutMs,
|
|
2578
|
-
abortSignal: options.abortSignal
|
|
2865
|
+
abortSignal: options.abortSignal,
|
|
2866
|
+
metadata: { __krnlTelemetryParentSpanId: telemetryHandle.spanId }
|
|
2579
2867
|
});
|
|
2580
2868
|
if (nestedResult.status !== "COMPLETED") {
|
|
2581
2869
|
throw new Error(nestedResult.error || `Nested orchestration "${childOrchId}" failed.`);
|
|
@@ -2623,8 +2911,13 @@ var ServiceFacade = class {
|
|
|
2623
2911
|
});
|
|
2624
2912
|
}
|
|
2625
2913
|
if (cmdResult.status === "FAILED" || orchestrationResult?.status === "FAILED") {
|
|
2626
|
-
|
|
2914
|
+
const error = new Error(orchestrationResult?.error || cmdResult.error || `[ServiceFacade:${this.id}] Orchestration failed.`);
|
|
2915
|
+
telemetryHandle.end(error);
|
|
2916
|
+
serviceTelemetryHandle.end(error);
|
|
2917
|
+
throw error;
|
|
2627
2918
|
}
|
|
2919
|
+
telemetryHandle.end();
|
|
2920
|
+
serviceTelemetryHandle.end();
|
|
2628
2921
|
return cmdResult.data;
|
|
2629
2922
|
}
|
|
2630
2923
|
/**
|
|
@@ -3283,9 +3576,9 @@ var ServiceRuntime = class {
|
|
|
3283
3576
|
// src/discovery/ServiceDiscovery.ts
|
|
3284
3577
|
var ServiceDiscovery = class {
|
|
3285
3578
|
peers = /* @__PURE__ */ new Map();
|
|
3286
|
-
registerPeer(
|
|
3287
|
-
this.peers.set(
|
|
3288
|
-
id,
|
|
3579
|
+
registerPeer(id2, name, endpoints) {
|
|
3580
|
+
this.peers.set(id2, {
|
|
3581
|
+
id: id2,
|
|
3289
3582
|
name,
|
|
3290
3583
|
endpoints,
|
|
3291
3584
|
lastSeen: Date.now()
|
|
@@ -3294,8 +3587,8 @@ var ServiceDiscovery = class {
|
|
|
3294
3587
|
getPeers() {
|
|
3295
3588
|
return Array.from(this.peers.values());
|
|
3296
3589
|
}
|
|
3297
|
-
findPeer(
|
|
3298
|
-
return this.peers.get(
|
|
3590
|
+
findPeer(id2) {
|
|
3591
|
+
return this.peers.get(id2);
|
|
3299
3592
|
}
|
|
3300
3593
|
};
|
|
3301
3594
|
|
|
@@ -3749,7 +4042,30 @@ var FunctionalityOrchestration = class {
|
|
|
3749
4042
|
|
|
3750
4043
|
// src/index.ts
|
|
3751
4044
|
import * as gutts from "@dinilmusick/gutts";
|
|
4045
|
+
|
|
4046
|
+
// src/execution/execution-controller.ts
|
|
4047
|
+
var DefaultExecutionController = class {
|
|
4048
|
+
providers = /* @__PURE__ */ new Map();
|
|
4049
|
+
executions = /* @__PURE__ */ new Map();
|
|
4050
|
+
register(provider) {
|
|
4051
|
+
this.providers.set(provider.id, provider);
|
|
4052
|
+
}
|
|
4053
|
+
async execute(request, providerId) {
|
|
4054
|
+
const provider = providerId ? this.providers.get(providerId) : this.providers.values().next().value;
|
|
4055
|
+
if (!provider) throw new Error("No execution provider is registered.");
|
|
4056
|
+
const result = await provider.execute(request);
|
|
4057
|
+
this.executions.set(result.executionId, provider);
|
|
4058
|
+
return result;
|
|
4059
|
+
}
|
|
4060
|
+
async cancel(executionId) {
|
|
4061
|
+
const provider = this.executions.get(executionId);
|
|
4062
|
+
if (!provider) throw new Error(`Unknown execution: ${executionId}`);
|
|
4063
|
+
await provider.cancel(executionId);
|
|
4064
|
+
this.executions.delete(executionId);
|
|
4065
|
+
}
|
|
4066
|
+
};
|
|
3752
4067
|
export {
|
|
4068
|
+
DefaultExecutionController,
|
|
3753
4069
|
EventBus,
|
|
3754
4070
|
FunctionalityFacade,
|
|
3755
4071
|
FunctionalityOrchestration,
|
|
@@ -3770,6 +4086,7 @@ export {
|
|
|
3770
4086
|
ServiceRegistry,
|
|
3771
4087
|
ServiceRuntime,
|
|
3772
4088
|
ServiceStateStore,
|
|
4089
|
+
TelemetryController,
|
|
3773
4090
|
UdpProtocolAdapter,
|
|
3774
4091
|
WebSocketProtocolAdapter,
|
|
3775
4092
|
WorkerExecutionBoundary,
|
|
@@ -3778,7 +4095,10 @@ export {
|
|
|
3778
4095
|
createServiceDefinition,
|
|
3779
4096
|
createServiceFacade,
|
|
3780
4097
|
createServiceProxy,
|
|
4098
|
+
deltaResources,
|
|
3781
4099
|
gutts,
|
|
4100
|
+
sampleResources,
|
|
4101
|
+
telemetryNow,
|
|
3782
4102
|
validateOrchestrationDAG,
|
|
3783
4103
|
validateServiceDefinition
|
|
3784
4104
|
};
|