smart-home-engine 1.18.2 → 1.19.1

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.
@@ -1,4 +1,4 @@
1
- import{m as O}from"./monaco-langs-Dt8a9eeo.js";import{t as I}from"./index-AuL9VYgt.js";/*!-----------------------------------------------------------------------------
1
+ import{m as O}from"./monaco-langs-Dt8a9eeo.js";import{t as I}from"./index-BAMNkTvJ.js";/*!-----------------------------------------------------------------------------
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
3
  * Version: 0.52.2(404545bded1df6ffa41ea0af4e8ddb219018c6c1)
4
4
  * Released under the MIT license
@@ -172,7 +172,7 @@
172
172
  }
173
173
  })();
174
174
  </script>
175
- <script type="module" crossorigin src="/assets/index-AuL9VYgt.js"></script>
175
+ <script type="module" crossorigin src="/assets/index-BAMNkTvJ.js"></script>
176
176
  <link rel="modulepreload" crossorigin href="/assets/monaco-langs-Dt8a9eeo.js">
177
177
  <link rel="stylesheet" crossorigin href="/assets/monaco-langs-DyX1CsEw.css">
178
178
  <link rel="stylesheet" crossorigin href="/assets/index-nf1nG74s.css">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "smart-home-engine",
3
- "version": "1.18.2",
3
+ "version": "1.19.1",
4
4
  "description": "Node.js based script runner for use in MQTT based Smart Home environments",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
package/src/index.js CHANGED
@@ -194,14 +194,15 @@ const _global = {};
194
194
 
195
195
  // ── Event-loop heartbeat ─────────────────────────────────────────────────────
196
196
  let _blockingScript = null;
197
+ let _blockingScriptTs = 0; // timestamp when the last _dispatch() call finished
197
198
 
198
199
  /** Wrap a user callback dispatch so the heartbeat can identify the active script. */
199
200
  function _dispatch(label, fn) {
200
201
  _blockingScript = label;
201
202
  fn();
202
- setImmediate(() => {
203
- _blockingScript = null;
204
- });
203
+ // Record end-time synchronously — no setImmediate, which would race with the
204
+ // heartbeat timer when blocking occurs inside a poll-phase (I/O) callback.
205
+ _blockingScriptTs = Date.now();
205
206
  }
206
207
 
207
208
  // Sun scheduling
@@ -328,6 +329,23 @@ let _mqttMsgCount = 0;
328
329
  let _mqttMsgTs = Date.now();
329
330
  let _prevCpuUsage = process.cpuUsage();
330
331
 
332
+ // perf_hooks — event loop utilization + delay histogram (always-on, minimal overhead)
333
+ const { PerformanceObserver, monitorEventLoopDelay, performance } = require('perf_hooks');
334
+ let _prevElu = performance.eventLoopUtilization();
335
+ const _elHisto = monitorEventLoopDelay({ resolution: 20 });
336
+ _elHisto.enable();
337
+
338
+ // GC observer — log only significant GC pauses (>=50ms); never spams on normal minor GCs
339
+ const _gcKinds = { 1: 'minor', 2: 'major', 4: 'incremental', 8: 'weaken' };
340
+ new PerformanceObserver((list) => {
341
+ for (const entry of list.getEntries()) {
342
+ if (entry.duration >= 50) {
343
+ const kind = _gcKinds[entry.detail?.kind] ?? 'gc';
344
+ log.warn(`GC ${kind} pause ${Math.round(entry.duration)}ms`);
345
+ }
346
+ }
347
+ }).observe({ type: 'gc', buffered: false });
348
+
331
349
  // Register runtime stats provider for GET /she/status
332
350
  require('./web/server').setStatsProvider(() => {
333
351
  let topics = 0;
@@ -341,6 +359,11 @@ require('./web/server').setStatsProvider(() => {
341
359
  const cpuDelta = process.cpuUsage(_prevCpuUsage);
342
360
  _prevCpuUsage = process.cpuUsage();
343
361
  const cpuPercent = elapsed > 0 ? Math.round(((cpuDelta.user + cpuDelta.system) / 1000 / (elapsed * 1000)) * 1000) / 10 : 0;
362
+ const eluDelta = performance.eventLoopUtilization(_prevElu);
363
+ _prevElu = performance.eventLoopUtilization();
364
+ const elMeanMs = Math.round(_elHisto.mean / 1e6);
365
+ const elMaxMs = Math.round(_elHisto.max / 1e6);
366
+ _elHisto.reset();
344
367
  const mem = process.memoryUsage();
345
368
  const memMb = Math.round(mem.rss / 1048576);
346
369
  const core = shedb.getCore();
@@ -378,6 +401,9 @@ require('./web/server').setStatsProvider(() => {
378
401
  handlers: subscriptions.length + varSubscriptions.length + mqttEventCallbacks.length,
379
402
  memMb,
380
403
  cpuPercent,
404
+ eluPercent: Math.round(eluDelta.utilization * 100),
405
+ elMeanMs,
406
+ elMaxMs,
381
407
  };
382
408
  });
383
409
 
@@ -1487,9 +1513,11 @@ function start() {
1487
1513
  const _hbTimer = setInterval(() => {
1488
1514
  const now = Date.now();
1489
1515
  const lag = now - _lastBeat - _hbInterval;
1516
+ const prevBeat = _lastBeat;
1490
1517
  _lastBeat = now;
1491
1518
  if (lag > _hbThreshold) {
1492
- const label = _blockingScript ?? 'unknown';
1519
+ // Attribute to a script only if it dispatched a callback since the previous beat.
1520
+ const label = _blockingScriptTs >= prevBeat ? (_blockingScript ?? 'unknown') : 'unknown';
1493
1521
  if (lag > 2000) {
1494
1522
  log.warn(`event loop blocked ${lag}ms — script: ${label}`);
1495
1523
  } else {