@camstack/addon-pipeline 1.2.94 → 1.2.95
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/{addon-utils-DnUCCZVx.js → addon-utils-UMWiMAxR.js} +1 -1
- package/dist/audio-analyzer/index.js +58 -4
- package/dist/audio-analyzer/index.mjs +56 -2
- package/dist/detection-pipeline/index.js +194 -6
- package/dist/detection-pipeline/index.mjs +191 -3
- package/dist/{dist-XbrYiMV3.mjs → dist-C49o1k7u.mjs} +316 -2
- package/dist/{dist-BbRv3bM2.js → dist-hyryByiw.js} +333 -1
- package/dist/{event-loop-stall-monitor-CFWrOZ6G.mjs → event-loop-stall-monitor-CfxZBgNi.mjs} +1 -1
- package/dist/{event-loop-stall-monitor-D9hqbc68.js → event-loop-stall-monitor-DPNTzGOT.js} +1 -1
- package/dist/{lazy-sharp-U0EtN7_C.js → lazy-sharp-Dxg6UeW-.js} +1 -1
- package/dist/motion-wasm/index.js +2 -2
- package/dist/motion-wasm/index.mjs +1 -1
- package/dist/pipeline-runner/index.js +4 -4
- package/dist/pipeline-runner/index.mjs +3 -3
- package/dist/process-memory-B9-UD7Rp.js +78 -0
- package/dist/process-memory-DXOB6eHX.mjs +66 -0
- package/dist/recorder/index.js +423 -47
- package/dist/recorder/index.mjs +422 -46
- package/dist/session-decode/decode-worker-child.js +2 -2
- package/dist/session-decode/decode-worker-child.mjs +1 -1
- package/dist/stream-broker/_stub.js +1 -1
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-BNOPhQ-y.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-CF-c0cDZ.mjs} +3 -3
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BjvmJK_d.mjs +26 -0
- package/dist/stream-broker/{hostInit-DCV2-mSi.mjs → hostInit-Cpcf2hDB.mjs} +3 -3
- package/dist/stream-broker/index.js +25 -7
- package/dist/stream-broker/index.mjs +25 -7
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/dist/{worker-protocol-CNC-ZcU3.js → worker-protocol-DR_a77D5.js} +1 -1
- package/dist/{worker-protocol-D0ewr67U.mjs → worker-protocol-DqQ2GI4M.mjs} +1 -1
- package/package.json +12 -7
- package/python/inference_pool.py +178 -3
- package/python/test_inference_pool_backpressure.py +7 -1
- package/python/test_inference_pool_memstats.py +146 -0
- package/dist/node-topology-platform-BkR_k6WT.mjs +0 -15
- package/dist/node-topology-platform-CFZ7F4xW.js +0 -20
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DMyOrQHq.mjs +0 -26
|
@@ -22,7 +22,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
22
22
|
}) : target, mod));
|
|
23
23
|
//#endregion
|
|
24
24
|
let node_crypto = require("node:crypto");
|
|
25
|
-
//#region ../types/dist/event-category-
|
|
25
|
+
//#region ../types/dist/event-category-XfKNtfCc.mjs
|
|
26
26
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
27
27
|
EventCategory["SystemBoot"] = "system.boot";
|
|
28
28
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -61,6 +61,22 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
61
61
|
EventCategory["AddonInstalled"] = "addon.installed";
|
|
62
62
|
EventCategory["AddonUninstalled"] = "addon.uninstalled";
|
|
63
63
|
EventCategory["AddonCrashed"] = "addon.crashed";
|
|
64
|
+
/**
|
|
65
|
+
* A RUNNER the D6 crash circuit-breaker gave up on — terminal.
|
|
66
|
+
*
|
|
67
|
+
* `AddonCrashed` is the routine, self-healing fact ("it crashed; it is being
|
|
68
|
+
* respawned"); this is the one that never resolves itself. Emitted exactly
|
|
69
|
+
* once per trip, by `process-service.ts`, carrying the node, the runner, the
|
|
70
|
+
* addons it hosted and the crash count that tripped the breaker.
|
|
71
|
+
*
|
|
72
|
+
* It exists because a runner marked terminally `failed` used to be SILENT:
|
|
73
|
+
* on 2026-08-18 the `recorder` runner died of three unhandled ffmpeg spawn
|
|
74
|
+
* errors, the breaker stopped respawning it (correctly), `/health` kept
|
|
75
|
+
* returning 200, and fleet-wide recording was gone for 3h15 before the
|
|
76
|
+
* operator's phone told him. The Notification Center's system-event intake
|
|
77
|
+
* consumes this category and maps it to the `addon-crash-loop` kind.
|
|
78
|
+
*/
|
|
79
|
+
EventCategory["AddonRunnerFailed"] = "addon.runner-failed";
|
|
64
80
|
EventCategory["AddonError"] = "addon.error";
|
|
65
81
|
EventCategory["AddonPageReady"] = "addon.page-ready";
|
|
66
82
|
EventCategory["AddonWidgetReady"] = "addon.widget-ready";
|
|
@@ -16094,6 +16110,7 @@ var NcSystemEventKindSchema = _enum([
|
|
|
16094
16110
|
"node-offline",
|
|
16095
16111
|
"node-inference-unavailable",
|
|
16096
16112
|
"detection-blind",
|
|
16113
|
+
"addon-crash-loop",
|
|
16097
16114
|
"addon-update-available",
|
|
16098
16115
|
"server-update-available",
|
|
16099
16116
|
"alarm-triggered",
|
|
@@ -36448,6 +36465,303 @@ function maskUrlCredentials(rawUrl) {
|
|
|
36448
36465
|
return rawUrl;
|
|
36449
36466
|
}
|
|
36450
36467
|
}
|
|
36468
|
+
var MB = 1024 * 1024;
|
|
36469
|
+
var DEFAULT_POOL_MEMORY_POLICY = {
|
|
36470
|
+
sampleIntervalMs: 6e4,
|
|
36471
|
+
baselineSettleSamples: 5,
|
|
36472
|
+
baselineSampleCount: 3,
|
|
36473
|
+
restartMultiple: 4,
|
|
36474
|
+
floorBytes: 1024 * MB,
|
|
36475
|
+
ceilingBytes: 3072 * MB,
|
|
36476
|
+
cooldownMs: 30 * 6e4,
|
|
36477
|
+
maxRestartsPerWindow: 6,
|
|
36478
|
+
restartWindowMs: 1440 * 6e4
|
|
36479
|
+
};
|
|
36480
|
+
/**
|
|
36481
|
+
* Resolve the policy from env overrides (`CAMSTACK_POOL_MEM_*`). Garbage or
|
|
36482
|
+
* absent values keep the default — an operator typo must never disable the
|
|
36483
|
+
* bound or set it to zero.
|
|
36484
|
+
*/
|
|
36485
|
+
function resolvePoolMemoryPolicy(env) {
|
|
36486
|
+
const num = (key, fallback, min) => {
|
|
36487
|
+
const raw = env[key];
|
|
36488
|
+
if (raw === void 0) return fallback;
|
|
36489
|
+
const parsed = Number(raw);
|
|
36490
|
+
return Number.isFinite(parsed) && parsed >= min ? parsed : fallback;
|
|
36491
|
+
};
|
|
36492
|
+
const d = DEFAULT_POOL_MEMORY_POLICY;
|
|
36493
|
+
return {
|
|
36494
|
+
sampleIntervalMs: num("CAMSTACK_POOL_MEM_INTERVAL_MS", d.sampleIntervalMs, 5e3),
|
|
36495
|
+
baselineSettleSamples: d.baselineSettleSamples,
|
|
36496
|
+
baselineSampleCount: d.baselineSampleCount,
|
|
36497
|
+
restartMultiple: num("CAMSTACK_POOL_MEM_MULTIPLE", d.restartMultiple, 1.5),
|
|
36498
|
+
floorBytes: num("CAMSTACK_POOL_MEM_FLOOR_MB", d.floorBytes / MB, 128) * MB,
|
|
36499
|
+
ceilingBytes: num("CAMSTACK_POOL_MEM_CEILING_MB", d.ceilingBytes / MB, 256) * MB,
|
|
36500
|
+
cooldownMs: num("CAMSTACK_POOL_MEM_COOLDOWN_MS", d.cooldownMs, 6e4),
|
|
36501
|
+
maxRestartsPerWindow: num("CAMSTACK_POOL_MEM_MAX_RESTARTS", d.maxRestartsPerWindow, 1),
|
|
36502
|
+
restartWindowMs: num("CAMSTACK_POOL_MEM_RESTART_WINDOW_MS", d.restartWindowMs, 6e4)
|
|
36503
|
+
};
|
|
36504
|
+
}
|
|
36505
|
+
/** Parse the fields this watchdog needs out of `/proc/<pid>/status` text.
|
|
36506
|
+
* Returns null when VmRSS is missing (dead pid, kernel thread, bad read). */
|
|
36507
|
+
function parseProcStatus(text) {
|
|
36508
|
+
const kb = (label) => {
|
|
36509
|
+
const match = text.match(new RegExp(`^${label}:\\s+(\\d+)\\s*kB`, "m"));
|
|
36510
|
+
return match ? Number(match[1]) * 1024 : null;
|
|
36511
|
+
};
|
|
36512
|
+
const rssBytes = kb("VmRSS");
|
|
36513
|
+
if (rssBytes === null) return null;
|
|
36514
|
+
const threadsMatch = text.match(/^Threads:\s+(\d+)/m);
|
|
36515
|
+
return {
|
|
36516
|
+
rssBytes,
|
|
36517
|
+
vmBytes: kb("VmSize") ?? 0,
|
|
36518
|
+
hwmBytes: kb("VmHWM") ?? 0,
|
|
36519
|
+
swapBytes: kb("VmSwap") ?? 0,
|
|
36520
|
+
threads: threadsMatch ? Number(threadsMatch[1]) : 0
|
|
36521
|
+
};
|
|
36522
|
+
}
|
|
36523
|
+
function initialPoolMemoryState() {
|
|
36524
|
+
return {
|
|
36525
|
+
settleSeen: 0,
|
|
36526
|
+
baselineWindow: [],
|
|
36527
|
+
baselineBytes: null,
|
|
36528
|
+
restartsAt: [],
|
|
36529
|
+
lastRestartAt: null
|
|
36530
|
+
};
|
|
36531
|
+
}
|
|
36532
|
+
function median(values) {
|
|
36533
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
36534
|
+
return sorted[Math.floor(sorted.length / 2)];
|
|
36535
|
+
}
|
|
36536
|
+
function advanceBaseline(state, rssBytes, policy) {
|
|
36537
|
+
if (state.baselineBytes !== null) return state;
|
|
36538
|
+
if (state.settleSeen < policy.baselineSettleSamples) return {
|
|
36539
|
+
...state,
|
|
36540
|
+
settleSeen: state.settleSeen + 1
|
|
36541
|
+
};
|
|
36542
|
+
const window = [...state.baselineWindow, rssBytes];
|
|
36543
|
+
if (window.length < policy.baselineSampleCount) return {
|
|
36544
|
+
...state,
|
|
36545
|
+
baselineWindow: window
|
|
36546
|
+
};
|
|
36547
|
+
return {
|
|
36548
|
+
...state,
|
|
36549
|
+
baselineWindow: window,
|
|
36550
|
+
baselineBytes: median(window)
|
|
36551
|
+
};
|
|
36552
|
+
}
|
|
36553
|
+
/** The one place a pool's restart threshold is computed. */
|
|
36554
|
+
function poolMemoryThreshold(baselineBytes, policy) {
|
|
36555
|
+
if (baselineBytes === null) return policy.ceilingBytes;
|
|
36556
|
+
return Math.min(policy.ceilingBytes, Math.max(policy.floorBytes, policy.restartMultiple * baselineBytes));
|
|
36557
|
+
}
|
|
36558
|
+
function pruneRestarts(restartsAt, nowMs, policy) {
|
|
36559
|
+
return restartsAt.filter((t) => nowMs - t < policy.restartWindowMs);
|
|
36560
|
+
}
|
|
36561
|
+
/**
|
|
36562
|
+
* Evaluate one RSS sample. Pure: returns the successor state plus the verdict.
|
|
36563
|
+
* The caller performs (and logs) the restart, then commits it via
|
|
36564
|
+
* {@link commitWatchdogRestart}.
|
|
36565
|
+
*/
|
|
36566
|
+
function evaluatePoolMemory(state, rssBytes, nowMs, policy) {
|
|
36567
|
+
const next = advanceBaseline(state, rssBytes, policy);
|
|
36568
|
+
const thresholdBytes = poolMemoryThreshold(next.baselineBytes, policy);
|
|
36569
|
+
if (rssBytes <= thresholdBytes) return {
|
|
36570
|
+
state: next,
|
|
36571
|
+
action: next.baselineBytes === null ? "baseline-pending" : "ok",
|
|
36572
|
+
baselineBytes: next.baselineBytes,
|
|
36573
|
+
thresholdBytes
|
|
36574
|
+
};
|
|
36575
|
+
const inWindow = pruneRestarts(next.restartsAt, nowMs, policy);
|
|
36576
|
+
const pruned = {
|
|
36577
|
+
...next,
|
|
36578
|
+
restartsAt: inWindow
|
|
36579
|
+
};
|
|
36580
|
+
if (inWindow.length >= policy.maxRestartsPerWindow) return {
|
|
36581
|
+
state: pruned,
|
|
36582
|
+
action: "exhausted",
|
|
36583
|
+
baselineBytes: next.baselineBytes,
|
|
36584
|
+
thresholdBytes
|
|
36585
|
+
};
|
|
36586
|
+
if (pruned.lastRestartAt !== null && nowMs - pruned.lastRestartAt < policy.cooldownMs) return {
|
|
36587
|
+
state: pruned,
|
|
36588
|
+
action: "cooldown",
|
|
36589
|
+
baselineBytes: next.baselineBytes,
|
|
36590
|
+
thresholdBytes
|
|
36591
|
+
};
|
|
36592
|
+
return {
|
|
36593
|
+
state: pruned,
|
|
36594
|
+
action: "restart",
|
|
36595
|
+
baselineBytes: next.baselineBytes,
|
|
36596
|
+
thresholdBytes
|
|
36597
|
+
};
|
|
36598
|
+
}
|
|
36599
|
+
/** Record a performed watchdog restart: budget consumed, baseline reset —
|
|
36600
|
+
* the recreated pool is a NEW process and gets a fresh settle window. */
|
|
36601
|
+
function commitWatchdogRestart(state, nowMs) {
|
|
36602
|
+
return {
|
|
36603
|
+
...initialPoolMemoryState(),
|
|
36604
|
+
restartsAt: [...state.restartsAt, nowMs],
|
|
36605
|
+
lastRestartAt: nowMs
|
|
36606
|
+
};
|
|
36607
|
+
}
|
|
36608
|
+
/** Reset baseline tracking (pool process replaced OUTSIDE the watchdog —
|
|
36609
|
+
* kernel OOM kill + respawn, idle-reaper eviction, tuning respawn). The
|
|
36610
|
+
* restart budget is kept: it bounds the WATCHDOG, not the pool. */
|
|
36611
|
+
function resetPoolBaseline(state) {
|
|
36612
|
+
return {
|
|
36613
|
+
...initialPoolMemoryState(),
|
|
36614
|
+
restartsAt: state.restartsAt,
|
|
36615
|
+
lastRestartAt: state.lastRestartAt
|
|
36616
|
+
};
|
|
36617
|
+
}
|
|
36618
|
+
/**
|
|
36619
|
+
* Pick ONE pool to restart this sweep — the worst overage ratio. Restarting
|
|
36620
|
+
* several pools at once (e.g. after a model rollout grew every baseline)
|
|
36621
|
+
* would take detection down on every camera simultaneously; one per sweep
|
|
36622
|
+
* means the survivors keep serving while the worst offender reloads, and the
|
|
36623
|
+
* next sweep (one interval later) takes the next one.
|
|
36624
|
+
*/
|
|
36625
|
+
function pickRestartCandidate(candidates) {
|
|
36626
|
+
if (candidates.length === 0) return null;
|
|
36627
|
+
let worst = candidates[0];
|
|
36628
|
+
for (const c of candidates) if (c.rssBytes / c.thresholdBytes > worst.rssBytes / worst.thresholdBytes) worst = c;
|
|
36629
|
+
return worst.key;
|
|
36630
|
+
}
|
|
36631
|
+
var PoolMemoryWatchdog = class {
|
|
36632
|
+
pools = /* @__PURE__ */ new Map();
|
|
36633
|
+
timer = null;
|
|
36634
|
+
sweeping = false;
|
|
36635
|
+
stopped = false;
|
|
36636
|
+
opts;
|
|
36637
|
+
now;
|
|
36638
|
+
setTimer;
|
|
36639
|
+
clearTimer;
|
|
36640
|
+
constructor(opts) {
|
|
36641
|
+
this.opts = opts;
|
|
36642
|
+
this.now = opts.now ?? (() => Date.now());
|
|
36643
|
+
this.setTimer = opts.setTimer ?? ((fn, ms) => setTimeout(fn, ms));
|
|
36644
|
+
this.clearTimer = opts.clearTimer ?? ((t) => clearTimeout(t));
|
|
36645
|
+
}
|
|
36646
|
+
start() {
|
|
36647
|
+
if (this.timer || this.stopped) return;
|
|
36648
|
+
this.arm();
|
|
36649
|
+
}
|
|
36650
|
+
stop() {
|
|
36651
|
+
this.stopped = true;
|
|
36652
|
+
if (this.timer) {
|
|
36653
|
+
this.clearTimer(this.timer);
|
|
36654
|
+
this.timer = null;
|
|
36655
|
+
}
|
|
36656
|
+
}
|
|
36657
|
+
arm() {
|
|
36658
|
+
const timer = this.setTimer(() => {
|
|
36659
|
+
this.sweep().finally(() => {
|
|
36660
|
+
if (!this.stopped) this.arm();
|
|
36661
|
+
});
|
|
36662
|
+
}, this.opts.policy.sampleIntervalMs);
|
|
36663
|
+
if (typeof timer.unref === "function") timer.unref();
|
|
36664
|
+
this.timer = timer;
|
|
36665
|
+
}
|
|
36666
|
+
/** One sweep: sample → log every pool → restart at most one. Public so the
|
|
36667
|
+
* loop is testable without fake global timers. */
|
|
36668
|
+
async sweep() {
|
|
36669
|
+
if (this.sweeping) return;
|
|
36670
|
+
this.sweeping = true;
|
|
36671
|
+
try {
|
|
36672
|
+
await this.doSweep();
|
|
36673
|
+
} catch (err) {
|
|
36674
|
+
this.opts.log.warn("pool memory sweep failed", { meta: { error: err instanceof Error ? err.message : String(err) } });
|
|
36675
|
+
} finally {
|
|
36676
|
+
this.sweeping = false;
|
|
36677
|
+
}
|
|
36678
|
+
}
|
|
36679
|
+
async doSweep() {
|
|
36680
|
+
const nowMs = this.now();
|
|
36681
|
+
const samples = await this.opts.sample();
|
|
36682
|
+
const candidates = [];
|
|
36683
|
+
const verdictByKey = /* @__PURE__ */ new Map();
|
|
36684
|
+
for (const t of samples) {
|
|
36685
|
+
const tracked = this.pools.get(t.key);
|
|
36686
|
+
let state = tracked?.state ?? initialPoolMemoryState();
|
|
36687
|
+
if (tracked && tracked.pids.length > 0 && !samePids(tracked.pids, t.pids)) {
|
|
36688
|
+
this.opts.log.warn("pool process changed outside the watchdog — re-baselining", { meta: {
|
|
36689
|
+
poolKey: t.key,
|
|
36690
|
+
previousPids: tracked.pids,
|
|
36691
|
+
pids: t.pids
|
|
36692
|
+
} });
|
|
36693
|
+
state = resetPoolBaseline(state);
|
|
36694
|
+
}
|
|
36695
|
+
const verdict = evaluatePoolMemory(state, t.rssBytes, nowMs, this.opts.policy);
|
|
36696
|
+
this.pools.set(t.key, {
|
|
36697
|
+
state: verdict.state,
|
|
36698
|
+
pids: t.pids
|
|
36699
|
+
});
|
|
36700
|
+
verdictByKey.set(t.key, verdict);
|
|
36701
|
+
this.opts.log.info("pool memory", { meta: {
|
|
36702
|
+
poolKey: t.key,
|
|
36703
|
+
pids: t.pids,
|
|
36704
|
+
rssMb: Math.round(t.rssBytes / MB),
|
|
36705
|
+
baselineMb: verdict.baselineBytes === null ? null : Math.round(verdict.baselineBytes / MB),
|
|
36706
|
+
thresholdMb: Math.round(verdict.thresholdBytes / MB),
|
|
36707
|
+
action: verdict.action,
|
|
36708
|
+
...t.meta
|
|
36709
|
+
} });
|
|
36710
|
+
if (verdict.action === "restart") candidates.push({
|
|
36711
|
+
key: t.key,
|
|
36712
|
+
rssBytes: t.rssBytes,
|
|
36713
|
+
thresholdBytes: verdict.thresholdBytes
|
|
36714
|
+
});
|
|
36715
|
+
else if (verdict.action === "cooldown") this.opts.log.warn("pool over memory threshold but inside restart cooldown", { meta: {
|
|
36716
|
+
poolKey: t.key,
|
|
36717
|
+
rssMb: Math.round(t.rssBytes / MB),
|
|
36718
|
+
thresholdMb: Math.round(verdict.thresholdBytes / MB),
|
|
36719
|
+
cooldownMs: this.opts.policy.cooldownMs
|
|
36720
|
+
} });
|
|
36721
|
+
else if (verdict.action === "exhausted") this.opts.log.error("pool memory watchdog gave up — restart budget exhausted, pool leaks faster than restarts can pay for; needs a heap profile (py-spy / tracemalloc)", { meta: {
|
|
36722
|
+
poolKey: t.key,
|
|
36723
|
+
rssMb: Math.round(t.rssBytes / MB),
|
|
36724
|
+
thresholdMb: Math.round(verdict.thresholdBytes / MB),
|
|
36725
|
+
maxRestartsPerWindow: this.opts.policy.maxRestartsPerWindow,
|
|
36726
|
+
restartWindowMs: this.opts.policy.restartWindowMs
|
|
36727
|
+
} });
|
|
36728
|
+
}
|
|
36729
|
+
for (const key of [...this.pools.keys()]) if (!samples.some((t) => t.key === key)) this.pools.delete(key);
|
|
36730
|
+
const pickedKey = pickRestartCandidate(candidates);
|
|
36731
|
+
if (pickedKey === null) return;
|
|
36732
|
+
const picked = candidates.find((c) => c.key === pickedKey);
|
|
36733
|
+
const verdict = verdictByKey.get(pickedKey);
|
|
36734
|
+
const tracked = this.pools.get(pickedKey);
|
|
36735
|
+
const restartsInWindow = tracked.state.restartsAt.length + 1;
|
|
36736
|
+
this.opts.log.warn("pool memory watchdog restarting pool — RSS over threshold", { meta: {
|
|
36737
|
+
poolKey: pickedKey,
|
|
36738
|
+
pids: tracked.pids,
|
|
36739
|
+
rssMb: Math.round(picked.rssBytes / MB),
|
|
36740
|
+
thresholdMb: Math.round(picked.thresholdBytes / MB),
|
|
36741
|
+
baselineMb: verdict.baselineBytes === null ? null : Math.round(verdict.baselineBytes / MB),
|
|
36742
|
+
restartsInWindow,
|
|
36743
|
+
deferredCandidates: candidates.filter((c) => c.key !== pickedKey).map((c) => c.key)
|
|
36744
|
+
} });
|
|
36745
|
+
try {
|
|
36746
|
+
await this.opts.restart(pickedKey);
|
|
36747
|
+
this.pools.set(pickedKey, {
|
|
36748
|
+
state: commitWatchdogRestart(tracked.state, this.now()),
|
|
36749
|
+
pids: []
|
|
36750
|
+
});
|
|
36751
|
+
} catch (err) {
|
|
36752
|
+
this.opts.log.error("pool memory watchdog restart failed", { meta: {
|
|
36753
|
+
poolKey: pickedKey,
|
|
36754
|
+
error: err instanceof Error ? err.message : String(err)
|
|
36755
|
+
} });
|
|
36756
|
+
}
|
|
36757
|
+
}
|
|
36758
|
+
};
|
|
36759
|
+
function samePids(a, b) {
|
|
36760
|
+
if (a.length !== b.length) return false;
|
|
36761
|
+
const sortedA = [...a].sort((x, y) => x - y);
|
|
36762
|
+
const sortedB = [...b].sort((x, y) => x - y);
|
|
36763
|
+
return sortedA.every((v, i) => v === sortedB[i]);
|
|
36764
|
+
}
|
|
36451
36765
|
/**
|
|
36452
36766
|
* Fixed-capacity ring buffer. When full, push() overwrites the oldest entry.
|
|
36453
36767
|
* drain() returns up to maxCount items in FIFO order and removes them.
|
|
@@ -36935,6 +37249,12 @@ Object.defineProperty(exports, "OpsLogEntrySchema", {
|
|
|
36935
37249
|
return OpsLogEntrySchema;
|
|
36936
37250
|
}
|
|
36937
37251
|
});
|
|
37252
|
+
Object.defineProperty(exports, "PoolMemoryWatchdog", {
|
|
37253
|
+
enumerable: true,
|
|
37254
|
+
get: function() {
|
|
37255
|
+
return PoolMemoryWatchdog;
|
|
37256
|
+
}
|
|
37257
|
+
});
|
|
36938
37258
|
Object.defineProperty(exports, "RATE_CONTROL_RELAXED", {
|
|
36939
37259
|
enumerable: true,
|
|
36940
37260
|
get: function() {
|
|
@@ -37223,6 +37543,12 @@ Object.defineProperty(exports, "parseJsonUnknown", {
|
|
|
37223
37543
|
return parseJsonUnknown;
|
|
37224
37544
|
}
|
|
37225
37545
|
});
|
|
37546
|
+
Object.defineProperty(exports, "parseProcStatus", {
|
|
37547
|
+
enumerable: true,
|
|
37548
|
+
get: function() {
|
|
37549
|
+
return parseProcStatus;
|
|
37550
|
+
}
|
|
37551
|
+
});
|
|
37226
37552
|
Object.defineProperty(exports, "parseProfileBrokerId", {
|
|
37227
37553
|
enumerable: true,
|
|
37228
37554
|
get: function() {
|
|
@@ -37277,6 +37603,12 @@ Object.defineProperty(exports, "resolveEgressDecodeHwAccel", {
|
|
|
37277
37603
|
return resolveEgressDecodeHwAccel;
|
|
37278
37604
|
}
|
|
37279
37605
|
});
|
|
37606
|
+
Object.defineProperty(exports, "resolvePoolMemoryPolicy", {
|
|
37607
|
+
enumerable: true,
|
|
37608
|
+
get: function() {
|
|
37609
|
+
return resolvePoolMemoryPolicy;
|
|
37610
|
+
}
|
|
37611
|
+
});
|
|
37280
37612
|
Object.defineProperty(exports, "resolveRecordingProfiles", {
|
|
37281
37613
|
enumerable: true,
|
|
37282
37614
|
get: function() {
|
package/dist/{event-loop-stall-monitor-CFWrOZ6G.mjs → event-loop-stall-monitor-CfxZBgNi.mjs}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { U as hfModelUrl, a as COCO_80_LABELS, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS } from "./dist-C49o1k7u.mjs";
|
|
2
2
|
import { PerformanceObserver } from "node:perf_hooks";
|
|
3
3
|
//#region src/detection-pipeline/registry/model-catalogs.ts
|
|
4
4
|
var HF_REPO = "camstack/camstack-models";
|
|
@@ -2,8 +2,8 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_dist = require("../dist-
|
|
6
|
-
const require_lazy_sharp = require("../lazy-sharp-
|
|
5
|
+
const require_dist = require("../dist-hyryByiw.js");
|
|
6
|
+
const require_lazy_sharp = require("../lazy-sharp-Dxg6UeW-.js");
|
|
7
7
|
let node_path = require("node:path");
|
|
8
8
|
let node_fs = require("node:fs");
|
|
9
9
|
//#region src/motion-wasm/wasm-motion-detector.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { H as evaluateZoneRules, K as motionDetectionCapability, _t as DeviceType, mt as BaseAddon, yt as hydrateSchema } from "../dist-C49o1k7u.mjs";
|
|
2
2
|
import { t as getSharp } from "../lazy-sharp-6oymT_yf.mjs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { readFileSync } from "node:fs";
|
|
@@ -2,11 +2,11 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_dist = require("../dist-
|
|
6
|
-
const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-
|
|
7
|
-
const require_worker_protocol = require("../worker-protocol-
|
|
5
|
+
const require_dist = require("../dist-hyryByiw.js");
|
|
6
|
+
const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-DPNTzGOT.js");
|
|
7
|
+
const require_worker_protocol = require("../worker-protocol-DR_a77D5.js");
|
|
8
8
|
const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
|
|
9
|
-
const require_lazy_sharp = require("../lazy-sharp-
|
|
9
|
+
const require_lazy_sharp = require("../lazy-sharp-Dxg6UeW-.js");
|
|
10
10
|
const require_remote_restream = require("../remote-restream-BYbAsgUf.js");
|
|
11
11
|
let sharp = require("sharp");
|
|
12
12
|
sharp = require_dist.__toESM(sharp);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { At as
|
|
2
|
-
import { c as getStepDefinition, t as attributeStall } from "../event-loop-stall-monitor-
|
|
3
|
-
import { a as nativeLeaseSettingEnv, t as isWorkerReply } from "../worker-protocol-
|
|
1
|
+
import { At as boolean, Ct as nodePin, Ft as object, I as deriveDetailCropRect, J as pickDetailCropConvention, Lt as string, M as customAction, Mt as lazy, Nt as literal, Ot as _enum, P as defineCustomActions, Pt as number, Y as pickNativeLeaseOverride, Z as pipelineRunnerCapability, c as DEFAULT_DETAIL_CROP_CONVENTION, ct as errMsg, d as DEVICE_BACKEND_TO_FORMAT, kt as array, mt as BaseAddon, vt as createEvent, zt as EventCategory } from "../dist-C49o1k7u.mjs";
|
|
2
|
+
import { c as getStepDefinition, t as attributeStall } from "../event-loop-stall-monitor-CfxZBgNi.mjs";
|
|
3
|
+
import { a as nativeLeaseSettingEnv, t as isWorkerReply } from "../worker-protocol-DqQ2GI4M.mjs";
|
|
4
4
|
import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
|
|
5
5
|
import { t as getSharp } from "../lazy-sharp-6oymT_yf.mjs";
|
|
6
6
|
import { i as withDetectionIntent, n as profileForStreamId, t as isRemoteRestream } from "../remote-restream-Ci7RXNGb.mjs";
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
const require_dist = require("./dist-hyryByiw.js");
|
|
2
|
+
let node_child_process = require("node:child_process");
|
|
3
|
+
let node_fs = require("node:fs");
|
|
4
|
+
node_fs = require_dist.__toESM(node_fs);
|
|
5
|
+
//#region src/shared/node-topology-platform.ts
|
|
6
|
+
/**
|
|
7
|
+
* Pick a node's `{ platform, arch }` from the cluster topology. Returns an empty
|
|
8
|
+
* object when the topology is missing or the node is absent (caller falls back).
|
|
9
|
+
*/
|
|
10
|
+
function pickNodePlatformArch(topology, nodeId) {
|
|
11
|
+
const entry = topology?.find((n) => n.id === nodeId);
|
|
12
|
+
if (!entry) return {};
|
|
13
|
+
return {
|
|
14
|
+
platform: entry.platform,
|
|
15
|
+
arch: entry.arch
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/shared/process-memory.ts
|
|
20
|
+
/**
|
|
21
|
+
* Read a child process's memory footprint for the pool memory watchdog.
|
|
22
|
+
*
|
|
23
|
+
* Linux (the fleet): parse `/proc/<pid>/status` — RSS, VmSize, VmHWM (peak
|
|
24
|
+
* RSS ≈ getrusage maxrss), VmSwap and Threads in one 4 KB read, no exec.
|
|
25
|
+
* macOS (dev only): `ps -o rss=` gives RSS alone; the extended fields read 0.
|
|
26
|
+
*
|
|
27
|
+
* Returns null when the pid is gone or unreadable — the CALLER logs the
|
|
28
|
+
* dropped sample (a pool the watchdog silently stopped seeing is a bound
|
|
29
|
+
* that silently stopped existing).
|
|
30
|
+
*
|
|
31
|
+
* The parse itself (`parseProcStatus`) lives in `@camstack/types` next to the
|
|
32
|
+
* watchdog policy so it is unit-tested once and shared with
|
|
33
|
+
* `addon-post-analysis`, which cannot import this addon. Only the `fs` read
|
|
34
|
+
* lives here.
|
|
35
|
+
*/
|
|
36
|
+
var IS_LINUX = process.platform === "linux";
|
|
37
|
+
async function readProcessMemory(pid) {
|
|
38
|
+
if (IS_LINUX) try {
|
|
39
|
+
return require_dist.parseProcStatus(await node_fs.promises.readFile(`/proc/${pid}/status`, "utf8"));
|
|
40
|
+
} catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
return readViaPs(pid);
|
|
44
|
+
}
|
|
45
|
+
function readViaPs(pid) {
|
|
46
|
+
return new Promise((resolve) => {
|
|
47
|
+
(0, node_child_process.execFile)("ps", [
|
|
48
|
+
"-o",
|
|
49
|
+
"rss=",
|
|
50
|
+
"-p",
|
|
51
|
+
String(pid)
|
|
52
|
+
], { timeout: 2e3 }, (err, stdout) => {
|
|
53
|
+
if (err) return resolve(null);
|
|
54
|
+
const kb = Number(stdout.trim());
|
|
55
|
+
if (!Number.isFinite(kb) || kb <= 0) return resolve(null);
|
|
56
|
+
resolve({
|
|
57
|
+
rssBytes: kb * 1024,
|
|
58
|
+
vmBytes: 0,
|
|
59
|
+
hwmBytes: 0,
|
|
60
|
+
swapBytes: 0,
|
|
61
|
+
threads: 0
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
//#endregion
|
|
67
|
+
Object.defineProperty(exports, "pickNodePlatformArch", {
|
|
68
|
+
enumerable: true,
|
|
69
|
+
get: function() {
|
|
70
|
+
return pickNodePlatformArch;
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
Object.defineProperty(exports, "readProcessMemory", {
|
|
74
|
+
enumerable: true,
|
|
75
|
+
get: function() {
|
|
76
|
+
return readProcessMemory;
|
|
77
|
+
}
|
|
78
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { q as parseProcStatus } from "./dist-C49o1k7u.mjs";
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
3
|
+
import * as fs from "node:fs";
|
|
4
|
+
//#region src/shared/node-topology-platform.ts
|
|
5
|
+
/**
|
|
6
|
+
* Pick a node's `{ platform, arch }` from the cluster topology. Returns an empty
|
|
7
|
+
* object when the topology is missing or the node is absent (caller falls back).
|
|
8
|
+
*/
|
|
9
|
+
function pickNodePlatformArch(topology, nodeId) {
|
|
10
|
+
const entry = topology?.find((n) => n.id === nodeId);
|
|
11
|
+
if (!entry) return {};
|
|
12
|
+
return {
|
|
13
|
+
platform: entry.platform,
|
|
14
|
+
arch: entry.arch
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region src/shared/process-memory.ts
|
|
19
|
+
/**
|
|
20
|
+
* Read a child process's memory footprint for the pool memory watchdog.
|
|
21
|
+
*
|
|
22
|
+
* Linux (the fleet): parse `/proc/<pid>/status` — RSS, VmSize, VmHWM (peak
|
|
23
|
+
* RSS ≈ getrusage maxrss), VmSwap and Threads in one 4 KB read, no exec.
|
|
24
|
+
* macOS (dev only): `ps -o rss=` gives RSS alone; the extended fields read 0.
|
|
25
|
+
*
|
|
26
|
+
* Returns null when the pid is gone or unreadable — the CALLER logs the
|
|
27
|
+
* dropped sample (a pool the watchdog silently stopped seeing is a bound
|
|
28
|
+
* that silently stopped existing).
|
|
29
|
+
*
|
|
30
|
+
* The parse itself (`parseProcStatus`) lives in `@camstack/types` next to the
|
|
31
|
+
* watchdog policy so it is unit-tested once and shared with
|
|
32
|
+
* `addon-post-analysis`, which cannot import this addon. Only the `fs` read
|
|
33
|
+
* lives here.
|
|
34
|
+
*/
|
|
35
|
+
var IS_LINUX = process.platform === "linux";
|
|
36
|
+
async function readProcessMemory(pid) {
|
|
37
|
+
if (IS_LINUX) try {
|
|
38
|
+
return parseProcStatus(await fs.promises.readFile(`/proc/${pid}/status`, "utf8"));
|
|
39
|
+
} catch {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
return readViaPs(pid);
|
|
43
|
+
}
|
|
44
|
+
function readViaPs(pid) {
|
|
45
|
+
return new Promise((resolve) => {
|
|
46
|
+
execFile("ps", [
|
|
47
|
+
"-o",
|
|
48
|
+
"rss=",
|
|
49
|
+
"-p",
|
|
50
|
+
String(pid)
|
|
51
|
+
], { timeout: 2e3 }, (err, stdout) => {
|
|
52
|
+
if (err) return resolve(null);
|
|
53
|
+
const kb = Number(stdout.trim());
|
|
54
|
+
if (!Number.isFinite(kb) || kb <= 0) return resolve(null);
|
|
55
|
+
resolve({
|
|
56
|
+
rssBytes: kb * 1024,
|
|
57
|
+
vmBytes: 0,
|
|
58
|
+
hwmBytes: 0,
|
|
59
|
+
swapBytes: 0,
|
|
60
|
+
threads: 0
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
//#endregion
|
|
66
|
+
export { pickNodePlatformArch as n, readProcessMemory as t };
|