@omen.foundation/node-microservice-runtime 0.1.60 → 0.1.62
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/collector-manager.cjs +51 -17
- package/dist/collector-manager.d.ts.map +1 -1
- package/dist/collector-manager.js +62 -23
- package/dist/collector-manager.js.map +1 -1
- package/dist/runtime.cjs +1 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +2 -1
- package/dist/runtime.js.map +1 -1
- package/package.json +1 -1
- package/src/collector-manager.ts +64 -22
- package/src/runtime.ts +2 -1
|
@@ -146,6 +146,11 @@ async function fetchClickHouseCredentials(env) {
|
|
|
146
146
|
return credentials;
|
|
147
147
|
}
|
|
148
148
|
function getCollectorStoragePath() {
|
|
149
|
+
const productionPath = '/opt/beam/collectors';
|
|
150
|
+
const productionVersionPath = (0, path_1.join)(productionPath, COLLECTOR_VERSION);
|
|
151
|
+
if ((0, fs_1.existsSync)(productionPath)) {
|
|
152
|
+
return productionVersionPath;
|
|
153
|
+
}
|
|
149
154
|
const tempDir = process.env.TMPDIR || process.env.TMP || '/tmp';
|
|
150
155
|
return (0, path_1.join)(tempDir, 'beam', 'collectors', COLLECTOR_VERSION);
|
|
151
156
|
}
|
|
@@ -310,12 +315,42 @@ async function resolveCollector(allowDownload = true, logger) {
|
|
|
310
315
|
configPath: (0, fs_1.existsSync)(configPath) ? configPath : null,
|
|
311
316
|
};
|
|
312
317
|
}
|
|
313
|
-
function discoverCollectorViaUDP(timeoutMs =
|
|
318
|
+
function discoverCollectorViaUDP(timeoutMs = 1000) {
|
|
314
319
|
return new Promise((resolve) => {
|
|
315
320
|
const socket = dgram_1.default.createSocket('udp4');
|
|
316
321
|
const discovered = [];
|
|
317
322
|
let timeout;
|
|
323
|
+
let resolved = false;
|
|
318
324
|
const startTime = Date.now();
|
|
325
|
+
const safetyTimeout = setTimeout(() => {
|
|
326
|
+
if (!resolved) {
|
|
327
|
+
console.log(`[UDP Discovery] Safety timeout triggered - forcing resolution`);
|
|
328
|
+
resolved = true;
|
|
329
|
+
try {
|
|
330
|
+
socket.removeAllListeners();
|
|
331
|
+
socket.close();
|
|
332
|
+
}
|
|
333
|
+
catch (e) {
|
|
334
|
+
}
|
|
335
|
+
clearTimeout(timeout);
|
|
336
|
+
resolve(discovered.length > 0 ? discovered[0] : null);
|
|
337
|
+
}
|
|
338
|
+
}, timeoutMs + 100);
|
|
339
|
+
const doResolve = (result) => {
|
|
340
|
+
if (!resolved) {
|
|
341
|
+
resolved = true;
|
|
342
|
+
clearTimeout(timeout);
|
|
343
|
+
clearTimeout(safetyTimeout);
|
|
344
|
+
try {
|
|
345
|
+
socket.removeAllListeners();
|
|
346
|
+
socket.close();
|
|
347
|
+
}
|
|
348
|
+
catch (e) {
|
|
349
|
+
}
|
|
350
|
+
console.log(`[UDP Discovery] Resolving promise with result: ${result ? 'found' : 'null'}`);
|
|
351
|
+
resolve(result);
|
|
352
|
+
}
|
|
353
|
+
};
|
|
319
354
|
socket.on('message', (msg) => {
|
|
320
355
|
try {
|
|
321
356
|
const message = JSON.parse(msg.toString());
|
|
@@ -323,17 +358,16 @@ function discoverCollectorViaUDP(timeoutMs = 5000) {
|
|
|
323
358
|
discovered.push(message);
|
|
324
359
|
const elapsed = Date.now() - startTime;
|
|
325
360
|
console.log(`[UDP Discovery] Found collector after ${elapsed}ms: ${message.otlpEndpoint}`);
|
|
361
|
+
doResolve(discovered[0]);
|
|
326
362
|
}
|
|
327
363
|
}
|
|
328
364
|
catch (error) {
|
|
329
365
|
}
|
|
330
366
|
});
|
|
331
367
|
socket.on('error', (err) => {
|
|
332
|
-
clearTimeout(timeout);
|
|
333
|
-
socket.close();
|
|
334
368
|
const elapsed = Date.now() - startTime;
|
|
335
369
|
console.log(`[UDP Discovery] Socket error after ${elapsed}ms: ${err.message}`);
|
|
336
|
-
|
|
370
|
+
doResolve(null);
|
|
337
371
|
});
|
|
338
372
|
socket.bind(() => {
|
|
339
373
|
socket.setBroadcast(true);
|
|
@@ -346,13 +380,7 @@ function discoverCollectorViaUDP(timeoutMs = 5000) {
|
|
|
346
380
|
else {
|
|
347
381
|
console.log(`[UDP Discovery] Timeout after ${elapsed}ms, no collector found`);
|
|
348
382
|
}
|
|
349
|
-
|
|
350
|
-
socket.close(() => {
|
|
351
|
-
});
|
|
352
|
-
}
|
|
353
|
-
catch (closeError) {
|
|
354
|
-
}
|
|
355
|
-
resolve(discovered.length > 0 ? discovered[0] : null);
|
|
383
|
+
doResolve(discovered.length > 0 ? discovered[0] : null);
|
|
356
384
|
}, timeoutMs);
|
|
357
385
|
});
|
|
358
386
|
});
|
|
@@ -417,9 +445,10 @@ async function isCollectorRunning() {
|
|
|
417
445
|
try {
|
|
418
446
|
const udpStartTime = Date.now();
|
|
419
447
|
console.log('[UDP Discovery] Starting UDP discovery in isCollectorRunning()...');
|
|
420
|
-
|
|
448
|
+
console.log('[UDP Discovery] Calling discoverCollectorViaUDP(1000)...');
|
|
449
|
+
const discovered = await discoverCollectorViaUDP(1000);
|
|
421
450
|
const udpElapsed = Date.now() - udpStartTime;
|
|
422
|
-
console.log(`[UDP Discovery] UDP discovery promise resolved after ${udpElapsed}ms`);
|
|
451
|
+
console.log(`[UDP Discovery] UDP discovery promise resolved after ${udpElapsed}ms, result: ${discovered ? 'found' : 'null'}`);
|
|
423
452
|
if (discovered) {
|
|
424
453
|
console.log(`[UDP Discovery] Found collector in ${udpElapsed}ms: ${discovered.otlpEndpoint}`);
|
|
425
454
|
return {
|
|
@@ -435,7 +464,11 @@ async function isCollectorRunning() {
|
|
|
435
464
|
}
|
|
436
465
|
}
|
|
437
466
|
catch (error) {
|
|
438
|
-
|
|
467
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
468
|
+
console.log(`[UDP Discovery] Error in isCollectorRunning(): ${errorMsg}`);
|
|
469
|
+
if (error instanceof Error && error.stack) {
|
|
470
|
+
console.log(`[UDP Discovery] Error stack: ${error.stack}`);
|
|
471
|
+
}
|
|
439
472
|
}
|
|
440
473
|
console.log('[UDP Discovery] Returning default not-running status from isCollectorRunning()');
|
|
441
474
|
return {
|
|
@@ -785,13 +818,14 @@ async function discoverOrStartCollector(logger, standardOtelEnabled, env) {
|
|
|
785
818
|
}
|
|
786
819
|
}
|
|
787
820
|
if (!globalCollectorProcess) {
|
|
788
|
-
logger.info('[Collector]
|
|
821
|
+
logger.info('[Collector] Quick check for existing collector via UDP discovery (timeout: 1s, matching C#)...');
|
|
789
822
|
const udpStartTime = Date.now();
|
|
823
|
+
logger.info('[Collector] Calling isCollectorRunning()...');
|
|
790
824
|
const status = await isCollectorRunning();
|
|
791
825
|
const udpElapsed = Date.now() - udpStartTime;
|
|
792
|
-
logger.info(`[Collector]
|
|
826
|
+
logger.info(`[Collector] isCollectorRunning() returned after ${udpElapsed}ms: isRunning=${status.isRunning}, isReady=${status.isReady}, endpoint=${status.otlpEndpoint || 'none'}`);
|
|
793
827
|
if (status.isRunning && status.isReady && status.otlpEndpoint) {
|
|
794
|
-
logger.info(`[Collector] Found running collector at ${status.otlpEndpoint}`);
|
|
828
|
+
logger.info(`[Collector] Found running collector at ${status.otlpEndpoint}, will reuse it`);
|
|
795
829
|
return `http://${status.otlpEndpoint}`;
|
|
796
830
|
}
|
|
797
831
|
logger.info('[Collector] No existing collector found, will start new one...');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collector-manager.d.ts","sourceRoot":"","sources":["../src/collector-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,YAAY,EAAE,MAAM,eAAe,CAAC;AAOpD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAInC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAYpD,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAuCD;;GAEG;AACH,UAAU,qBAAqB;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAqCD;;;;GAIG;AACH,wBAAsB,0BAA0B,CAC9C,GAAG,EAAE,iBAAiB,GACrB,OAAO,CAAC,qBAAqB,CAAC,CAsDhC;
|
|
1
|
+
{"version":3,"file":"collector-manager.d.ts","sourceRoot":"","sources":["../src/collector-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,YAAY,EAAE,MAAM,eAAe,CAAC;AAOpD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAInC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAYpD,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAuCD;;GAEG;AACH,UAAU,qBAAqB;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAqCD;;;;GAIG;AACH,wBAAsB,0BAA0B,CAC9C,GAAG,EAAE,iBAAiB,GACrB,OAAO,CAAC,qBAAqB,CAAC,CAsDhC;AAuSD;;GAEG;AACH,wBAAgB,8BAA8B,IAAI;IAChD,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,aAAa,GAAG,KAAK,GAAG,SAAS,CAAC;CAC3C,CAoBA;AAED;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,eAAe,CAAC,CAuFnE;AA0BD;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAYjG;AAED;;;;GAIG;AACH,wBAAsB,6BAA6B,CACjD,GAAG,EAAE,iBAAiB,EACtB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAwCxB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,iBAAiB,GAAG,IAAI,CAsChE;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CACzC,GAAG,EAAE,iBAAiB,EACtB,SAAS,GAAE,MAAc,GACxB,MAAM,GAAG,IAAI,CA8Ef;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,MAAM,EACrB,GAAG,CAAC,EAAE,iBAAiB,GACtB,OAAO,CAAC;IAAE,OAAO,EAAE,YAAY,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAuNtD;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI;IAC3C,UAAU,EAAE,OAAO,CAAC;IACpB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CASA;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,MAAM,EACd,mBAAmB,EAAE,OAAO,EAC5B,GAAG,CAAC,EAAE,iBAAiB,GACtB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAyKxB"}
|
|
@@ -124,9 +124,18 @@ export async function fetchClickHouseCredentials(env) {
|
|
|
124
124
|
}
|
|
125
125
|
/**
|
|
126
126
|
* Gets the collector storage directory (similar to C# LocalApplicationData/beam/collectors/version)
|
|
127
|
+
* Checks production location first (pre-installed in Docker), then falls back to temp directory
|
|
127
128
|
*/
|
|
128
129
|
function getCollectorStoragePath() {
|
|
129
|
-
//
|
|
130
|
+
// Check production location first (pre-installed in Docker image at /opt/beam/collectors)
|
|
131
|
+
// This avoids runtime download delays (~12 seconds)
|
|
132
|
+
const productionPath = '/opt/beam/collectors';
|
|
133
|
+
const productionVersionPath = join(productionPath, COLLECTOR_VERSION);
|
|
134
|
+
// Use production path if it exists (Docker image pre-installed collector)
|
|
135
|
+
if (existsSync(productionPath)) {
|
|
136
|
+
return productionVersionPath;
|
|
137
|
+
}
|
|
138
|
+
// Fallback to temp directory (local development without Docker)
|
|
130
139
|
const tempDir = process.env.TMPDIR || process.env.TMP || '/tmp';
|
|
131
140
|
return join(tempDir, 'beam', 'collectors', COLLECTOR_VERSION);
|
|
132
141
|
}
|
|
@@ -314,12 +323,45 @@ async function resolveCollector(allowDownload = true, logger) {
|
|
|
314
323
|
/**
|
|
315
324
|
* Discovers collector via UDP broadcast
|
|
316
325
|
*/
|
|
317
|
-
function discoverCollectorViaUDP(timeoutMs =
|
|
326
|
+
function discoverCollectorViaUDP(timeoutMs = 1000) {
|
|
318
327
|
return new Promise((resolve) => {
|
|
319
328
|
const socket = dgram.createSocket('udp4');
|
|
320
329
|
const discovered = [];
|
|
321
330
|
let timeout;
|
|
331
|
+
let resolved = false; // Guard to prevent double resolution
|
|
322
332
|
const startTime = Date.now();
|
|
333
|
+
// Safety timeout - force resolve after timeout + 100ms buffer
|
|
334
|
+
const safetyTimeout = setTimeout(() => {
|
|
335
|
+
if (!resolved) {
|
|
336
|
+
console.log(`[UDP Discovery] Safety timeout triggered - forcing resolution`);
|
|
337
|
+
resolved = true;
|
|
338
|
+
try {
|
|
339
|
+
socket.removeAllListeners();
|
|
340
|
+
socket.close();
|
|
341
|
+
}
|
|
342
|
+
catch (e) {
|
|
343
|
+
// Ignore
|
|
344
|
+
}
|
|
345
|
+
clearTimeout(timeout);
|
|
346
|
+
resolve(discovered.length > 0 ? discovered[0] : null);
|
|
347
|
+
}
|
|
348
|
+
}, timeoutMs + 100);
|
|
349
|
+
const doResolve = (result) => {
|
|
350
|
+
if (!resolved) {
|
|
351
|
+
resolved = true;
|
|
352
|
+
clearTimeout(timeout);
|
|
353
|
+
clearTimeout(safetyTimeout);
|
|
354
|
+
try {
|
|
355
|
+
socket.removeAllListeners();
|
|
356
|
+
socket.close();
|
|
357
|
+
}
|
|
358
|
+
catch (e) {
|
|
359
|
+
// Ignore
|
|
360
|
+
}
|
|
361
|
+
console.log(`[UDP Discovery] Resolving promise with result: ${result ? 'found' : 'null'}`);
|
|
362
|
+
resolve(result);
|
|
363
|
+
}
|
|
364
|
+
};
|
|
323
365
|
socket.on('message', (msg) => {
|
|
324
366
|
try {
|
|
325
367
|
const message = JSON.parse(msg.toString());
|
|
@@ -328,6 +370,8 @@ function discoverCollectorViaUDP(timeoutMs = 5000) {
|
|
|
328
370
|
discovered.push(message);
|
|
329
371
|
const elapsed = Date.now() - startTime;
|
|
330
372
|
console.log(`[UDP Discovery] Found collector after ${elapsed}ms: ${message.otlpEndpoint}`);
|
|
373
|
+
// Resolve immediately when collector found
|
|
374
|
+
doResolve(discovered[0]);
|
|
331
375
|
}
|
|
332
376
|
}
|
|
333
377
|
catch (error) {
|
|
@@ -335,11 +379,9 @@ function discoverCollectorViaUDP(timeoutMs = 5000) {
|
|
|
335
379
|
}
|
|
336
380
|
});
|
|
337
381
|
socket.on('error', (err) => {
|
|
338
|
-
clearTimeout(timeout);
|
|
339
|
-
socket.close();
|
|
340
382
|
const elapsed = Date.now() - startTime;
|
|
341
383
|
console.log(`[UDP Discovery] Socket error after ${elapsed}ms: ${err.message}`);
|
|
342
|
-
|
|
384
|
+
doResolve(null);
|
|
343
385
|
});
|
|
344
386
|
socket.bind(() => {
|
|
345
387
|
socket.setBroadcast(true);
|
|
@@ -352,17 +394,7 @@ function discoverCollectorViaUDP(timeoutMs = 5000) {
|
|
|
352
394
|
else {
|
|
353
395
|
console.log(`[UDP Discovery] Timeout after ${elapsed}ms, no collector found`);
|
|
354
396
|
}
|
|
355
|
-
|
|
356
|
-
try {
|
|
357
|
-
socket.close(() => {
|
|
358
|
-
// Socket closed callback (optional, we don't wait for this)
|
|
359
|
-
});
|
|
360
|
-
}
|
|
361
|
-
catch (closeError) {
|
|
362
|
-
// Ignore close errors
|
|
363
|
-
}
|
|
364
|
-
// Return the first discovered collector immediately
|
|
365
|
-
resolve(discovered.length > 0 ? discovered[0] : null);
|
|
397
|
+
doResolve(discovered.length > 0 ? discovered[0] : null);
|
|
366
398
|
}, timeoutMs);
|
|
367
399
|
});
|
|
368
400
|
});
|
|
@@ -446,9 +478,10 @@ export async function isCollectorRunning() {
|
|
|
446
478
|
try {
|
|
447
479
|
const udpStartTime = Date.now();
|
|
448
480
|
console.log('[UDP Discovery] Starting UDP discovery in isCollectorRunning()...');
|
|
449
|
-
|
|
481
|
+
console.log('[UDP Discovery] Calling discoverCollectorViaUDP(1000)...');
|
|
482
|
+
const discovered = await discoverCollectorViaUDP(1000); // Match C#: 1 second max (10 attempts × 100ms)
|
|
450
483
|
const udpElapsed = Date.now() - udpStartTime;
|
|
451
|
-
console.log(`[UDP Discovery] UDP discovery promise resolved after ${udpElapsed}ms`);
|
|
484
|
+
console.log(`[UDP Discovery] UDP discovery promise resolved after ${udpElapsed}ms, result: ${discovered ? 'found' : 'null'}`);
|
|
452
485
|
if (discovered) {
|
|
453
486
|
console.log(`[UDP Discovery] Found collector in ${udpElapsed}ms: ${discovered.otlpEndpoint}`);
|
|
454
487
|
return {
|
|
@@ -465,7 +498,11 @@ export async function isCollectorRunning() {
|
|
|
465
498
|
}
|
|
466
499
|
catch (error) {
|
|
467
500
|
// Discovery failed, collector probably not running
|
|
468
|
-
|
|
501
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
502
|
+
console.log(`[UDP Discovery] Error in isCollectorRunning(): ${errorMsg}`);
|
|
503
|
+
if (error instanceof Error && error.stack) {
|
|
504
|
+
console.log(`[UDP Discovery] Error stack: ${error.stack}`);
|
|
505
|
+
}
|
|
469
506
|
}
|
|
470
507
|
console.log('[UDP Discovery] Returning default not-running status from isCollectorRunning()');
|
|
471
508
|
return {
|
|
@@ -929,16 +966,18 @@ export async function discoverOrStartCollector(logger, standardOtelEnabled, env)
|
|
|
929
966
|
globalCollectorStderr = [];
|
|
930
967
|
}
|
|
931
968
|
}
|
|
932
|
-
// First, check if collector is already running (via UDP discovery)
|
|
969
|
+
// First, quick check if collector is already running (via UDP discovery)
|
|
970
|
+
// Match C#: 10 attempts × 100ms = 1 second max (much faster than before)
|
|
933
971
|
// Skip UDP discovery if we already have a process reference (faster)
|
|
934
972
|
if (!globalCollectorProcess) {
|
|
935
|
-
logger.info('[Collector]
|
|
973
|
+
logger.info('[Collector] Quick check for existing collector via UDP discovery (timeout: 1s, matching C#)...');
|
|
936
974
|
const udpStartTime = Date.now();
|
|
975
|
+
logger.info('[Collector] Calling isCollectorRunning()...');
|
|
937
976
|
const status = await isCollectorRunning();
|
|
938
977
|
const udpElapsed = Date.now() - udpStartTime;
|
|
939
|
-
logger.info(`[Collector]
|
|
978
|
+
logger.info(`[Collector] isCollectorRunning() returned after ${udpElapsed}ms: isRunning=${status.isRunning}, isReady=${status.isReady}, endpoint=${status.otlpEndpoint || 'none'}`);
|
|
940
979
|
if (status.isRunning && status.isReady && status.otlpEndpoint) {
|
|
941
|
-
logger.info(`[Collector] Found running collector at ${status.otlpEndpoint}`);
|
|
980
|
+
logger.info(`[Collector] Found running collector at ${status.otlpEndpoint}, will reuse it`);
|
|
942
981
|
return `http://${status.otlpEndpoint}`;
|
|
943
982
|
}
|
|
944
983
|
logger.info('[Collector] No existing collector found, will start new one...');
|