@cocreate/server-telemetry 1.15.0 → 1.16.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/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ # [1.16.0](https://github.com/CoCreate-app/CoCreate-server-telemetry/compare/v1.15.0...v1.16.0) (2026-07-18)
2
+
3
+
4
+ ### Features
5
+
6
+ * streamline telemetry code by removing redundant comments and enhancing resource limit checks ([275c62c](https://github.com/CoCreate-app/CoCreate-server-telemetry/commit/275c62c52a484d743a2b84c108552839c786f243))
7
+
1
8
  # [1.15.0](https://github.com/CoCreate-app/CoCreate-server-telemetry/compare/v1.14.3...v1.15.0) (2026-07-17)
2
9
 
3
10
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cocreate/server-telemetry",
3
- "version": "1.15.0",
3
+ "version": "1.16.0",
4
4
  "description": "CoCreate-server-telemetry",
5
5
  "keywords": [
6
6
  "cocreate-server-telemetry",
package/src/index.js CHANGED
@@ -26,10 +26,6 @@ import os from 'node:os';
26
26
  import Config from '@cocreate/config';
27
27
  import { getValueFromObject } from '@cocreate/utils';
28
28
 
29
-
30
- // ==============================================================================
31
- // Module-Level Sandbox State (ESM Singleton Container)
32
- // ==============================================================================
33
29
  let server = null; // Reference to the main CoCreateServer instance
34
30
  let activeIntervalId = null; // Storage for the core execution loop interval
35
31
  let lastCpuInfo = null; // Cache for the previous CPU telemetry sample
@@ -58,7 +54,6 @@ const defaults = {
58
54
  broadcast: true
59
55
  };
60
56
 
61
-
62
57
  /**
63
58
  * Reads memory allocations using a local-dev fallback if Linux /proc is unavailable.
64
59
  * Supports cross-platform safety (macOS and Windows environments).
@@ -108,7 +103,6 @@ export function readMemoryInfo() {
108
103
  }
109
104
  }
110
105
 
111
-
112
106
  /**
113
107
  * Reads CPU performance ticks across cores natively or using fallback trackers.
114
108
  *
@@ -144,7 +138,6 @@ export function readCpuInfo() {
144
138
  }
145
139
  }
146
140
 
147
-
148
141
  /**
149
142
  * Computes CPU core utilization percentages by comparing differential cycle ticks.
150
143
  *
@@ -175,7 +168,6 @@ export function calculateCpuUsage(cpuInfo1, cpuInfo2) {
175
168
  });
176
169
  }
177
170
 
178
-
179
171
  /**
180
172
  * Calculates a dynamic safety memory threshold percentage based on the physical core-to-memory ratio.
181
173
  * This is symmetrically checked locally in server-telemetry.js to align the 1-second emergency loops.
@@ -198,7 +190,6 @@ function calculateDynamicSafetyThreshold() {
198
190
  return Math.max(50, Math.min(90, maxSafePercentage));
199
191
  }
200
192
 
201
-
202
193
  /**
203
194
  * Dynamic Telemetry Ingestion Protocol.
204
195
  * Allows other platform modules (like server-mesh.js) to push specific performance
@@ -222,7 +213,6 @@ export function send(component, data) {
222
213
  }
223
214
  }
224
215
 
225
-
226
216
  /**
227
217
  * Core execution tick. Collects system specs, appends external custom registries,
228
218
  * and commits rolls to database buffer limits. Excludes event-emitter or callback leaks.
@@ -272,7 +262,6 @@ export function read() {
272
262
  rss: Math.round(processMemory.rss / 1024),
273
263
  external: Math.round(processMemory.external / 1024)
274
264
  },
275
- // Symmetrically merge custom component blocks directly into the heartbeat payload
276
265
  ...customTelemetryRegistry,
277
266
  timestamp: new Date().toISOString()
278
267
  };
@@ -280,13 +269,10 @@ export function read() {
280
269
  dbBuffer.push(JSON.parse(JSON.stringify(currentTelemetry)));
281
270
 
282
271
  // --- INSTANTANEOUS 1-SECOND OOM PROTECTION CHECK ---
283
- // If memory spikes above the threshold on any individual 1-second sample,
284
- // fire an immediate emergency signal to the Master process.
285
272
  let targetMemoryThreshold = telemetryConfig
286
273
  ? parseInt(getValueFromObject(telemetryConfig, 'server-telemetry.scaleUpMemoryThreshold'), 10)
287
274
  : 85;
288
275
 
289
- // Apply Dynamic Safety limits to 1s emergency checks if enabled (on by default)
290
276
  const isSafetyLimitsEnabled = getValueFromObject(telemetryConfig, 'server-telemetry.safetyLimits') !== false && getValueFromObject(telemetryConfig, 'server-telemetry.safetyLimits') !== 'false';
291
277
 
292
278
  if (isSafetyLimitsEnabled) {
@@ -297,7 +283,7 @@ export function read() {
297
283
  }
298
284
 
299
285
  if (currentTelemetry.memory.percentage >= targetMemoryThreshold) {
300
- const emergencyCooldown = 300000; // Throttle to maximum 1 emergency signal every 5 minutes per worker node
286
+ const emergencyCooldown = 300000;
301
287
  if (Date.now() - lastEmergencyAlertTimestamp >= emergencyCooldown) {
302
288
  lastEmergencyAlertTimestamp = Date.now();
303
289
  console.warn(`[@cocreate/server-telemetry] [EMERGENCY] Memory threshold breached on 1s tick (${currentTelemetry.memory.percentage}% >= ${targetMemoryThreshold}%). Dispatching direct system-up scaling alarm!`);
@@ -309,9 +295,51 @@ export function read() {
309
295
  }
310
296
  }
311
297
 
312
- // Dynamic Time-Staggering Check:
313
- // All workers write their own process stats, but their flush intervals are staggered
314
- // using a round-robin calculation to prevent massive write collisions.
298
+ // --- AUTOMATED INGRESS CORDON TRACKING (CLIENT-SIDE LOAD BALANCING) ---
299
+ // User-configurable limit nested inside safetyLimits, safetyOptions, or defined flat
300
+ const cordonMemoryThreshold = telemetryConfig
301
+ ? parseInt(
302
+ getValueFromObject(telemetryConfig, 'server-telemetry.safetyLimits.cordonMemoryThreshold') ||
303
+ getValueFromObject(telemetryConfig, 'server-telemetry.safetyOptions.cordonMemoryThreshold') ||
304
+ getValueFromObject(telemetryConfig, 'server-telemetry.cordonMemoryThreshold'), 10
305
+ )
306
+ : 90;
307
+
308
+ const cordonCpuThreshold = telemetryConfig
309
+ ? parseInt(
310
+ getValueFromObject(telemetryConfig, 'server-telemetry.safetyLimits.cordonCpuThreshold') ||
311
+ getValueFromObject(telemetryConfig, 'server-telemetry.safetyOptions.cordonCpuThreshold') ||
312
+ getValueFromObject(telemetryConfig, 'server-telemetry.cordonCpuThreshold'), 10
313
+ )
314
+ : 90;
315
+
316
+ const actualMemoryThreshold = isNaN(cordonMemoryThreshold) ? 90 : cordonMemoryThreshold;
317
+ const actualCpuThreshold = isNaN(cordonCpuThreshold) ? 90 : cordonCpuThreshold;
318
+
319
+ const isResourceLimitBreached = currentTelemetry.memory.percentage >= actualMemoryThreshold ||
320
+ currentTelemetry.cpu.totalUsage >= actualCpuThreshold;
321
+
322
+ const recoveryBuffer = 5;
323
+ const isResourceSafeToRecover = currentTelemetry.memory.percentage < (actualMemoryThreshold - recoveryBuffer) &&
324
+ currentTelemetry.cpu.totalUsage < (actualCpuThreshold - recoveryBuffer);
325
+
326
+ // Decoupled state execution: Telemetry acts as a sensor sending updates to the Server core.
327
+ // It relies on server.isCordon to verify if a state modification payload needs to be broadcast.
328
+ if (isResourceLimitBreached && !server.isCordon) {
329
+ server.send({
330
+ method: 'cordon',
331
+ broadcast: true,
332
+ active: true
333
+ });
334
+ } else if (!isResourceLimitBreached && server.isCordon && isResourceSafeToRecover) {
335
+ server.send({
336
+ method: 'cordon',
337
+ broadcast: true,
338
+ active: false
339
+ });
340
+ }
341
+
342
+ // Dynamic Time-Staggering Check
315
343
  const customWriteInterval = telemetryConfig
316
344
  ? parseInt(getValueFromObject(telemetryConfig, 'server-telemetry.writeInterval'), 10)
317
345
  : defaults.writeInterval;
@@ -327,12 +355,9 @@ export function read() {
327
355
  return currentTelemetry;
328
356
  }
329
357
 
330
-
331
358
  /**
332
359
  * Processes buffered raw tick records to calculate minimum, maximum, and average values.
333
360
  * Writes aggregated results as a single document utilizing standard server.crud structures.
334
- * Also emits the statistical telemetry directly to the IPC loop using fail-fast server.send().
335
- * Cleans up outdated database telemetry if retentionDays is configured.
336
361
  */
337
362
  export async function flushTelemetryToDatabase() {
338
363
  if (dbBuffer.length === 0) {
@@ -348,7 +373,6 @@ export async function flushTelemetryToDatabase() {
348
373
  const load1m = dbBuffer.map(sample => sample.system.loadavg[0]);
349
374
  const heapUsed = dbBuffer.map(sample => sample.process.heapUsed);
350
375
 
351
- // Compute statistical aggregates
352
376
  const cpuMin = Math.min(...cpuUsages);
353
377
  const cpuMax = Math.max(...cpuUsages);
354
378
  const cpuAvg = cpuUsages.reduce((sum, val) => sum + val, 0) / totalSamples;
@@ -362,7 +386,6 @@ export async function flushTelemetryToDatabase() {
362
386
 
363
387
  const lastSample = dbBuffer[totalSamples - 1];
364
388
 
365
- // Gather any custom component keys injected during the current buffer window
366
389
  const componentAggregates = {};
367
390
  for (const key of Object.keys(customTelemetryRegistry)) {
368
391
  componentAggregates[key] = lastSample[key] || null;
@@ -398,24 +421,19 @@ export async function flushTelemetryToDatabase() {
398
421
  worker_uptime: lastSample.process.uptime,
399
422
  max_heap_kb: maxHeap
400
423
  },
401
- // Save dynamic custom telemetry blocks
402
424
  custom: componentAggregates
403
425
  };
404
426
 
405
- // Clear local buffer immediately to avoid execution loop overlap
406
427
  dbBuffer = [];
407
428
  lastDbFlushTimestamp = Date.now();
408
429
 
409
- // 1. DISPATCH LIVE EVENT VIA SERVER SEND (FAIL-FAST)
410
- // Directly fire the 'telemetry' method upstream.
411
- // It should route cleanly or throw immediately.
430
+ // 1. DISPATCH LIVE EVENT VIA SERVER SEND
412
431
  server.send({
413
432
  method: 'telemetry',
414
433
  data: aggregatedPayload
415
434
  });
416
435
 
417
436
  // 2. WRITE HISTORICAL RECORD TO DATABASE
418
- // Target standard CoCreate server storage configuration using server.crud directly
419
437
  const dbResponse = await server.crud.send({
420
438
  method: 'object.create',
421
439
  array: 'system_telemetry',
@@ -434,7 +452,6 @@ export async function flushTelemetryToDatabase() {
434
452
  const isBroadcastEnabled = broadcastConfig !== false && broadcastConfig !== 'false';
435
453
 
436
454
  if (isBroadcastEnabled) {
437
- // Inject broadcast parameters onto the validated response object
438
455
  dbResponse.broadcast = broadcastConfig;
439
456
  server.wsManager.send(dbResponse);
440
457
  }
@@ -447,7 +464,6 @@ export async function flushTelemetryToDatabase() {
447
464
 
448
465
  const retentionDays = isNaN(configuredRetention) ? defaults.retentionDays : configuredRetention;
449
466
 
450
- // Only Worker 1 handles retention pruning to prevent lock disputes
451
467
  if (retentionDays > 0 && workerId === 1) {
452
468
  const cutoffDate = new Date();
453
469
  cutoffDate.setDate(cutoffDate.getDate() - retentionDays);
@@ -468,7 +484,6 @@ export async function flushTelemetryToDatabase() {
468
484
  }
469
485
  }
470
486
 
471
-
472
487
  /**
473
488
  * Returns the cached memory and system snapshot compiled during the last execution sweep.
474
489
  *
@@ -480,15 +495,10 @@ export function get() {
480
495
 
481
496
  /**
482
497
  * Integrates server-telemetry capabilities, loads configuration, and schedules staggered execution threads.
483
- * Returns the functional API contract directly instead of mutating the parent server context.
484
- *
485
- * @param {Object} serverCtx - The core instantiated server environment
486
- * @returns {Object} Functional API contract for the server-telemetry subsystem
487
498
  */
488
499
  export async function init(serverCtx) {
489
500
  server = serverCtx;
490
501
 
491
- // Define functional API contract
492
502
  const telemetryAPI = {
493
503
  init,
494
504
  stop,
@@ -501,7 +511,6 @@ export async function init(serverCtx) {
501
511
  flushTelemetryToDatabase
502
512
  };
503
513
 
504
- // Load nested telemetry parameters matching standard configuration queries
505
514
  telemetryConfig = await Config({
506
515
  'server-telemetry': ''
507
516
  });
@@ -518,16 +527,11 @@ export async function init(serverCtx) {
518
527
 
519
528
  const workerId = server.workerId;
520
529
  const totalWorkers = server.totalWorkers;
521
-
522
- // Staggered launch delays to prevent resource spikes during multi-worker server boots
523
- const staggeredDelay = (workerId * collectionInterval) + (totalWorkers * collectionInterval);
524
530
 
525
531
  stop();
526
532
 
527
533
  lastCpuInfo = readCpuInfo();
528
534
 
529
- // Mathematically offset the first write target so that worker logging phases
530
- // are perfectly staggered across the write window, avoiding write overlaps!
531
535
  const phaseOffset = ((workerId - 1) / totalWorkers) * customWriteInterval;
532
536
  lastDbFlushTimestamp = Date.now() - phaseOffset;
533
537
 
@@ -546,7 +550,6 @@ export function stop() {
546
550
  }
547
551
  }
548
552
 
549
- // Default export matches standard functional API entry contract
550
553
  export default {
551
554
  init,
552
555
  stop,