@camstack/addon-pipeline 1.2.618 → 1.2.619
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/audio-analyzer/index.js +3 -3
- package/dist/audio-analyzer/index.mjs +3 -3
- package/dist/{custom-model-catalog-Yu1sxc4A.js → custom-model-catalog-Cn0kRD3w.js} +2 -2
- package/dist/{custom-model-catalog-BT8HKaes.mjs → custom-model-catalog-CtwTRnkw.mjs} +2 -2
- package/dist/detection-pipeline/index.js +153 -6
- package/dist/detection-pipeline/index.mjs +153 -6
- package/dist/{dist-CGDR6bSg.js → dist-CKI0TPq_.js} +151 -83
- package/dist/{dist-OImyOnr3.mjs → dist-L2gIYUSW.mjs} +151 -83
- package/dist/{model-catalogs-Cj101H8x.mjs → model-catalogs-BEL5IntY.mjs} +1 -1
- package/dist/{model-catalogs-DV562sqJ.js → model-catalogs-CvjhHSYH.js} +1 -1
- package/dist/motion-wasm/index.js +1 -1
- package/dist/motion-wasm/index.mjs +1 -1
- package/dist/{node-DciF_ZRl.mjs → node-BTcllpO8.mjs} +1 -1
- package/dist/{node-CSFdbFlw.js → node-Cl9jPP-W.js} +1 -1
- package/dist/pipeline-runner/index.js +52 -20
- package/dist/pipeline-runner/index.mjs +52 -20
- package/dist/{process-memory-DjIov9TF.mjs → process-memory-BZysh_Ow.mjs} +1 -1
- package/dist/{process-memory-CJEkTpRM.js → process-memory-oCLpTRfC.js} +1 -1
- package/dist/recorder/index.js +2 -72
- package/dist/recorder/index.mjs +2 -72
- package/dist/{segment-demux-js-BsqG99U7.js → segment-demux-js-BYhSnRdH.js} +1 -1
- package/dist/{segment-demux-js-B5PU-E-G.mjs → segment-demux-js-CRLu3mac.mjs} +1 -1
- package/dist/stream-broker/_stub.js +2 -2
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-BZysHyCo.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-CUjRbxP-.mjs} +3 -3
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BaoBRCJs.mjs +26 -0
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-BRT-stIJ.mjs +26 -0
- package/dist/stream-broker/demux-worker-child.js +1 -1
- package/dist/stream-broker/demux-worker-child.mjs +1 -1
- package/dist/stream-broker/{hostInit-NqO2jvV2.mjs → hostInit-DXO96V0R.mjs} +3 -3
- package/dist/stream-broker/index.js +3 -3
- package/dist/stream-broker/index.mjs +3 -3
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/package.json +1 -1
- package/python/inference_pool.py +2 -0
- package/python/pool_platform.py +35 -0
- package/python/test_pool_platform.py +48 -0
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-C1yyuAzs.mjs +0 -26
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-TnEvW5tZ.mjs +0 -26
|
@@ -3,9 +3,9 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../chunk-emK7D4bc.js");
|
|
6
|
-
const require_dist = require("../dist-
|
|
7
|
-
const require_model_catalogs = require("../model-catalogs-
|
|
8
|
-
const require_process_memory = require("../process-memory-
|
|
6
|
+
const require_dist = require("../dist-CKI0TPq_.js");
|
|
7
|
+
const require_model_catalogs = require("../model-catalogs-CvjhHSYH.js");
|
|
8
|
+
const require_process_memory = require("../process-memory-oCLpTRfC.js");
|
|
9
9
|
let node_fs = require("node:fs");
|
|
10
10
|
node_fs = require_chunk.__toESM(node_fs);
|
|
11
11
|
let node_path = require("node:path");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { n as __require } from "../chunk-DnnnRqeS.mjs";
|
|
2
|
-
import { $ as audioAnalyzerCapability, F as PoolMemoryWatchdog, Kn as hydrateSchema, Mn as errMsg, Pn as BaseAddon, Q as audioAnalysisCapability, Qn as nodePin, Rt as mapAudioLabelToMacro, Wn as expandAudioChunkToF32le, h as DEFAULT_AUDIO_ANALYZER_CONFIG, hr as EventCategory, ln as resolvePoolMemoryPolicy, r as AUDIO_BACKEND_CHOICES, zn as audioChunkBytesPerSample } from "../dist-
|
|
3
|
-
import { n as AUDIO_CLASSIFIER_MODELS } from "../model-catalogs-
|
|
4
|
-
import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-
|
|
2
|
+
import { $ as audioAnalyzerCapability, F as PoolMemoryWatchdog, Kn as hydrateSchema, Mn as errMsg, Pn as BaseAddon, Q as audioAnalysisCapability, Qn as nodePin, Rt as mapAudioLabelToMacro, Wn as expandAudioChunkToF32le, h as DEFAULT_AUDIO_ANALYZER_CONFIG, hr as EventCategory, ln as resolvePoolMemoryPolicy, r as AUDIO_BACKEND_CHOICES, zn as audioChunkBytesPerSample } from "../dist-L2gIYUSW.mjs";
|
|
3
|
+
import { n as AUDIO_CLASSIFIER_MODELS } from "../model-catalogs-BEL5IntY.mjs";
|
|
4
|
+
import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-BZysh_Ow.mjs";
|
|
5
5
|
import * as fs from "node:fs";
|
|
6
6
|
import * as path$1 from "node:path";
|
|
7
7
|
import { ensureModel } from "@camstack/system/addon-utils";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
const require_dist = require("./dist-
|
|
2
|
-
const require_model_catalogs = require("./model-catalogs-
|
|
1
|
+
const require_dist = require("./dist-CKI0TPq_.js");
|
|
2
|
+
const require_model_catalogs = require("./model-catalogs-CvjhHSYH.js");
|
|
3
3
|
const require_worker_protocol = require("./worker-protocol-C-G8qmye.js");
|
|
4
4
|
let node_crypto = require("node:crypto");
|
|
5
5
|
//#region src/detection-pipeline/registry/effective-confidence.ts
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Mt as inferModelProvider, b as DEVICE_BACKEND_TO_FORMAT, et as audioKindId, f as COCO_80_LABELS, hn as stepModelRunsOnFormat, i as AUDIO_MACRO_LABELS, k as LABEL_SUPPLY_VOCABULARIES, p as COCO_TO_MACRO } from "./dist-
|
|
2
|
-
import { a as FACE_DETECTION_MODELS, c as OBJECT_DETECTION_MODELS, d as PLATE_OCR_MODELS, f as SEGMENTATION_REFINER_MODELS, i as CLIP_EMBEDDING_MODELS, l as PACKAGE_DETECTION_MODELS, n as AUDIO_CLASSIFIER_MODELS, o as FACE_EMBEDDING_MODELS, p as VEHICLE_CLASSIFIER_MODELS, r as BIRD_CLASSIFIER_MODELS, s as INSTANCE_SEGMENTATION_MODELS, t as ANIMAL_CLASSIFIER_MODELS, u as PLATE_DETECTION_MODELS } from "./model-catalogs-
|
|
1
|
+
import { Mt as inferModelProvider, b as DEVICE_BACKEND_TO_FORMAT, et as audioKindId, f as COCO_80_LABELS, hn as stepModelRunsOnFormat, i as AUDIO_MACRO_LABELS, k as LABEL_SUPPLY_VOCABULARIES, p as COCO_TO_MACRO } from "./dist-L2gIYUSW.mjs";
|
|
2
|
+
import { a as FACE_DETECTION_MODELS, c as OBJECT_DETECTION_MODELS, d as PLATE_OCR_MODELS, f as SEGMENTATION_REFINER_MODELS, i as CLIP_EMBEDDING_MODELS, l as PACKAGE_DETECTION_MODELS, n as AUDIO_CLASSIFIER_MODELS, o as FACE_EMBEDDING_MODELS, p as VEHICLE_CLASSIFIER_MODELS, r as BIRD_CLASSIFIER_MODELS, s as INSTANCE_SEGMENTATION_MODELS, t as ANIMAL_CLASSIFIER_MODELS, u as PLATE_DETECTION_MODELS } from "./model-catalogs-BEL5IntY.mjs";
|
|
3
3
|
import { t as isWorkerReply } from "./worker-protocol-D_NzPcnh.mjs";
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
5
5
|
//#region src/detection-pipeline/registry/effective-confidence.ts
|
|
@@ -3,11 +3,11 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../chunk-emK7D4bc.js");
|
|
6
|
-
const require_dist = require("../dist-
|
|
7
|
-
const require_node = require("../node-
|
|
8
|
-
const require_custom_model_catalog = require("../custom-model-catalog-
|
|
6
|
+
const require_dist = require("../dist-CKI0TPq_.js");
|
|
7
|
+
const require_node = require("../node-Cl9jPP-W.js");
|
|
8
|
+
const require_custom_model_catalog = require("../custom-model-catalog-Cn0kRD3w.js");
|
|
9
9
|
const require_lazy_sharp = require("../lazy-sharp-BuwKlQLR.js");
|
|
10
|
-
const require_process_memory = require("../process-memory-
|
|
10
|
+
const require_process_memory = require("../process-memory-oCLpTRfC.js");
|
|
11
11
|
let node_os = require("node:os");
|
|
12
12
|
node_os = require_chunk.__toESM(node_os);
|
|
13
13
|
let node_fs = require("node:fs");
|
|
@@ -1221,6 +1221,39 @@ async function terminateChild(proc, graceMs) {
|
|
|
1221
1221
|
}, graceMs);
|
|
1222
1222
|
});
|
|
1223
1223
|
}
|
|
1224
|
+
/**
|
|
1225
|
+
* How long a POISONED worker is given to write its stack after SIGUSR1,
|
|
1226
|
+
* before SIGTERM. `faulthandler` writes from a C signal handler, so a dump
|
|
1227
|
+
* takes milliseconds even while a native call holds the GIL; the bound is
|
|
1228
|
+
* there for the worker that cannot answer at all. Never more than ~2 s: the
|
|
1229
|
+
* recycle it delays is the one that hands the device back to the budget.
|
|
1230
|
+
*/
|
|
1231
|
+
var POOL_STACK_DUMP_WAIT_MS = 1500;
|
|
1232
|
+
/**
|
|
1233
|
+
* Ask a hung worker for every thread's Python stack (SIGUSR1, registered by
|
|
1234
|
+
* the pool with `faulthandler` → its stderr, which the host logs under the
|
|
1235
|
+
* worker label), then wait up to `waitMs` — or until it exits — so the dump
|
|
1236
|
+
* is written before the caller terminates it. Exported for tests.
|
|
1237
|
+
*/
|
|
1238
|
+
async function requestStackDump(proc, waitMs, platform = process.platform) {
|
|
1239
|
+
if (platform === "win32") return "unsupported";
|
|
1240
|
+
if (proc.exitCode !== null || proc.signalCode !== null) return "already-exited";
|
|
1241
|
+
try {
|
|
1242
|
+
proc.kill("SIGUSR1");
|
|
1243
|
+
} catch {
|
|
1244
|
+
return "signal-failed";
|
|
1245
|
+
}
|
|
1246
|
+
await new Promise((resolve) => {
|
|
1247
|
+
const done = () => {
|
|
1248
|
+
clearTimeout(timer);
|
|
1249
|
+
proc.removeListener("exit", done);
|
|
1250
|
+
resolve();
|
|
1251
|
+
};
|
|
1252
|
+
const timer = setTimeout(done, waitMs);
|
|
1253
|
+
proc.once("exit", done);
|
|
1254
|
+
});
|
|
1255
|
+
return "signalled";
|
|
1256
|
+
}
|
|
1224
1257
|
var PoolWorker = class {
|
|
1225
1258
|
process = null;
|
|
1226
1259
|
receiveBuffer = Buffer.alloc(0);
|
|
@@ -2012,7 +2045,30 @@ var PoolWorker = class {
|
|
|
2012
2045
|
if (this.recycling || this.exited || this.process === null) return;
|
|
2013
2046
|
this.recycling = true;
|
|
2014
2047
|
if (this.recycleBackstop) clearTimeout(this.recycleBackstop);
|
|
2015
|
-
|
|
2048
|
+
const proc = this.process;
|
|
2049
|
+
this.dumpStackOfPoisoned(proc).then(() => terminateChild(proc, POOL_WORKER_TERM_GRACE_MS));
|
|
2050
|
+
}
|
|
2051
|
+
/**
|
|
2052
|
+
* Before a POISONED worker is killed, ask it where it hung (SIGUSR1 →
|
|
2053
|
+
* `faulthandler`, bounded by {@link POOL_STACK_DUMP_WAIT_MS}) and say where
|
|
2054
|
+
* the answer went: the worker's stderr, which this host logs line by line as
|
|
2055
|
+
* `[<worker label>] …` warnings just before the exit line. A hang that is
|
|
2056
|
+
* killed without this leaves "it hung" as the whole record.
|
|
2057
|
+
*/
|
|
2058
|
+
async dumpStackOfPoisoned(proc) {
|
|
2059
|
+
if (this.poisonVerdict === null) return;
|
|
2060
|
+
const outcome = await requestStackDump(proc, POOL_STACK_DUMP_WAIT_MS);
|
|
2061
|
+
this.log.warn("poisoned pool worker asked for its stack before SIGTERM", { meta: {
|
|
2062
|
+
worker: this.opts.workerLabel,
|
|
2063
|
+
pid: proc.pid ?? null,
|
|
2064
|
+
runtime: this.opts.poolRuntime,
|
|
2065
|
+
device: this.opts.device ?? "default",
|
|
2066
|
+
reason: this.poisonVerdict.reason,
|
|
2067
|
+
outcome,
|
|
2068
|
+
signal: "SIGUSR1",
|
|
2069
|
+
waitedMs: outcome === "signalled" ? POOL_STACK_DUMP_WAIT_MS : 0,
|
|
2070
|
+
dumpWrittenTo: outcome === "signalled" ? `worker stderr — this log, lines prefixed [${this.opts.workerLabel}]` : "none"
|
|
2071
|
+
} });
|
|
2016
2072
|
}
|
|
2017
2073
|
rejectAll(err) {
|
|
2018
2074
|
const entries = [...this.pending.values()];
|
|
@@ -4359,6 +4415,53 @@ var InferenceDeviceLivenessSupervisor = class {
|
|
|
4359
4415
|
}
|
|
4360
4416
|
};
|
|
4361
4417
|
//#endregion
|
|
4418
|
+
//#region src/detection-pipeline/engine/frame-device-reelection.ts
|
|
4419
|
+
function routeLiveFrameDevice(input) {
|
|
4420
|
+
const requested = input.requestedDeviceKey;
|
|
4421
|
+
if (requested === void 0) return {
|
|
4422
|
+
kind: "as-elected",
|
|
4423
|
+
deviceKey: void 0
|
|
4424
|
+
};
|
|
4425
|
+
const from = input.unusable(requested);
|
|
4426
|
+
if (from === null) return {
|
|
4427
|
+
kind: "as-elected",
|
|
4428
|
+
deviceKey: requested
|
|
4429
|
+
};
|
|
4430
|
+
if (requested === input.defaultDeviceKey || input.unusable(input.defaultDeviceKey) !== null) return {
|
|
4431
|
+
kind: "no-alternative",
|
|
4432
|
+
deviceKey: requested,
|
|
4433
|
+
from
|
|
4434
|
+
};
|
|
4435
|
+
return {
|
|
4436
|
+
kind: "re-elected",
|
|
4437
|
+
deviceKey: void 0,
|
|
4438
|
+
from,
|
|
4439
|
+
to: input.defaultDeviceKey
|
|
4440
|
+
};
|
|
4441
|
+
}
|
|
4442
|
+
/**
|
|
4443
|
+
* Per camera, the routing last said — so a 6 fps camera says "re-elected"
|
|
4444
|
+
* once, not six times a second, and says it again when it is back.
|
|
4445
|
+
*/
|
|
4446
|
+
var FrameReelectionNotes = class {
|
|
4447
|
+
said = /* @__PURE__ */ new Map();
|
|
4448
|
+
note(deviceId, routing) {
|
|
4449
|
+
const previous = this.said.get(deviceId);
|
|
4450
|
+
if (routing.kind === "as-elected") {
|
|
4451
|
+
if (previous === void 0) return null;
|
|
4452
|
+
this.said.delete(deviceId);
|
|
4453
|
+
return routing.deviceKey !== void 0 ? {
|
|
4454
|
+
kind: "restored",
|
|
4455
|
+
deviceKey: routing.deviceKey
|
|
4456
|
+
} : null;
|
|
4457
|
+
}
|
|
4458
|
+
const state = `${routing.kind}|${routing.from.deviceKey}|${routing.from.state}`;
|
|
4459
|
+
if (previous === state) return null;
|
|
4460
|
+
this.said.set(deviceId, state);
|
|
4461
|
+
return routing;
|
|
4462
|
+
}
|
|
4463
|
+
};
|
|
4464
|
+
//#endregion
|
|
4362
4465
|
//#region src/detection-pipeline/engine/pool-memory-guard.ts
|
|
4363
4466
|
function createDetectionPoolMemoryGuard(source, logger) {
|
|
4364
4467
|
const log = logger.child("pool-memory");
|
|
@@ -9729,9 +9832,10 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
9729
9832
|
emit(`Image: ${imageWidth}×${imageHeight}`);
|
|
9730
9833
|
}
|
|
9731
9834
|
decodeMs = performance.now() - decodeT0;
|
|
9835
|
+
const liveDeviceKey = isRuntime && input.replay !== true && input.deviceId !== void 0 && input.sessionId === void 0 ? this.routeLiveFrameDevice(input.deviceKey, input.deviceId) : input.deviceKey;
|
|
9732
9836
|
const dispatchResolution = this.resolveStepsForDispatch({
|
|
9733
9837
|
steps: input.steps,
|
|
9734
|
-
deviceKey:
|
|
9838
|
+
deviceKey: liveDeviceKey,
|
|
9735
9839
|
deviceId: input.deviceId,
|
|
9736
9840
|
plane: input.plane
|
|
9737
9841
|
});
|
|
@@ -10871,6 +10975,49 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
10871
10975
|
* (`encodeModelByte`) that pool could never have served inference again even
|
|
10872
10976
|
* if its worker had come back.
|
|
10873
10977
|
*/
|
|
10978
|
+
/** Per camera, the last live-frame re-election said (see `frame-device-reelection.ts`). */
|
|
10979
|
+
frameReelections = new FrameReelectionNotes();
|
|
10980
|
+
/**
|
|
10981
|
+
* The deviceKey a live frame dispatches on: the elected one while it is
|
|
10982
|
+
* usable, else the node default pool. Each change is said once per camera,
|
|
10983
|
+
* naming the device — a camera whose frames silently moved pool, or were
|
|
10984
|
+
* silently refused, is the failure this exists to end.
|
|
10985
|
+
*/
|
|
10986
|
+
routeLiveFrameDevice(requestedDeviceKey, deviceId) {
|
|
10987
|
+
const routing = routeLiveFrameDevice({
|
|
10988
|
+
requestedDeviceKey,
|
|
10989
|
+
defaultDeviceKey: require_custom_model_catalog.deviceKeyOf(this.currentEngine),
|
|
10990
|
+
unusable: (key) => this.deviceLiveness.unusableReason(key)
|
|
10991
|
+
});
|
|
10992
|
+
const note = this.frameReelections.note(deviceId, routing);
|
|
10993
|
+
if (note !== null) {
|
|
10994
|
+
const tags = { tags: { deviceId } };
|
|
10995
|
+
if (note.kind === "re-elected") this.log.warn("elected inference device unusable — frames re-elected onto the default pool", {
|
|
10996
|
+
...tags,
|
|
10997
|
+
meta: {
|
|
10998
|
+
deviceKey: note.from.deviceKey,
|
|
10999
|
+
state: note.from.state,
|
|
11000
|
+
deaths: note.from.deaths,
|
|
11001
|
+
lastError: note.from.lastError,
|
|
11002
|
+
reElectedTo: note.to
|
|
11003
|
+
}
|
|
11004
|
+
});
|
|
11005
|
+
else if (note.kind === "no-alternative") this.log.warn("elected inference device unusable and no other pool here — frames refused", {
|
|
11006
|
+
...tags,
|
|
11007
|
+
meta: {
|
|
11008
|
+
deviceKey: note.from.deviceKey,
|
|
11009
|
+
state: note.from.state,
|
|
11010
|
+
deaths: note.from.deaths,
|
|
11011
|
+
lastError: note.from.lastError
|
|
11012
|
+
}
|
|
11013
|
+
});
|
|
11014
|
+
else this.log.info("elected inference device usable again — frames back on it", {
|
|
11015
|
+
...tags,
|
|
11016
|
+
meta: { deviceKey: note.deviceKey }
|
|
11017
|
+
});
|
|
11018
|
+
}
|
|
11019
|
+
return routing.deviceKey;
|
|
11020
|
+
}
|
|
10874
11021
|
refuseIfDeviceUnusable(deviceKey) {
|
|
10875
11022
|
const unhealthy = this.deviceLiveness.unusableReason(deviceKey);
|
|
10876
11023
|
if (unhealthy) throw new InferenceDeviceUnusableError(unhealthy);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { n as __require } from "../chunk-DnnnRqeS.mjs";
|
|
2
|
-
import { Bn as createEvent, Ct as evaluateZoneRules, F as PoolMemoryWatchdog, Gn as hfModelUrl, It as loadContributionCapability, Jt as pickClusterStepSettings, Kn as hydrateSchema, Kt as overlayClusterStepSettings, Mn as errMsg$1, O as LABEL_SUPPLY_MACRO, Pn as BaseAddon, Pt as linkedLabelStepId, Qn as nodePin, St as enumerateInferenceDevices, Wt as modelBindingKey, X as applyModelBoundSettings, Zt as pipelineExecutorCapability, _t as detectionPipelineCapability, bn as supportedRuntimes$1, ct as containingParentIndex, d as CLUSTER_MODEL_SCOPED_STEPS, fn as rootSuppliesOf, ft as defaultDeviceFor$1, g as DEFAULT_CLUSTER_STEP_SETTINGS, hn as stepModelRunsOnFormat, hr as EventCategory, in as resolveClusterStepModelId, ir as array, ln as resolvePoolMemoryPolicy, mr as union, n as APPLE_SA_TO_MACRO, pn as runtimeDevices$1, pr as string, q as YAMNET_TO_MACRO, st as collectModelBoundKeys, tr as sleep, ur as object, yt as edgetpuDelegateDevice } from "../dist-
|
|
3
|
-
import { c as readProcessCost } from "../node-
|
|
4
|
-
import { C as resolveModelDefaultConfidence, S as landmarkPrecisionVerdict, _ as ALL_STEPS, b as getStepDefinition, f as localFrameRegistry, g as ALL_PIPELINE_STEPS, l as resolveDefaultDetectionModel, n as mergeCustomModels, o as deviceKeyOf, r as buildSubtreeCanRun, s as resolveDeviceEngine, t as CustomModelCatalog, u as macroGateVerdict, v as getDefaultModelForFormat, x as resolveModelForFormat, y as getStep } from "../custom-model-catalog-
|
|
2
|
+
import { Bn as createEvent, Ct as evaluateZoneRules, F as PoolMemoryWatchdog, Gn as hfModelUrl, It as loadContributionCapability, Jt as pickClusterStepSettings, Kn as hydrateSchema, Kt as overlayClusterStepSettings, Mn as errMsg$1, O as LABEL_SUPPLY_MACRO, Pn as BaseAddon, Pt as linkedLabelStepId, Qn as nodePin, St as enumerateInferenceDevices, Wt as modelBindingKey, X as applyModelBoundSettings, Zt as pipelineExecutorCapability, _t as detectionPipelineCapability, bn as supportedRuntimes$1, ct as containingParentIndex, d as CLUSTER_MODEL_SCOPED_STEPS, fn as rootSuppliesOf, ft as defaultDeviceFor$1, g as DEFAULT_CLUSTER_STEP_SETTINGS, hn as stepModelRunsOnFormat, hr as EventCategory, in as resolveClusterStepModelId, ir as array, ln as resolvePoolMemoryPolicy, mr as union, n as APPLE_SA_TO_MACRO, pn as runtimeDevices$1, pr as string, q as YAMNET_TO_MACRO, st as collectModelBoundKeys, tr as sleep, ur as object, yt as edgetpuDelegateDevice } from "../dist-L2gIYUSW.mjs";
|
|
3
|
+
import { c as readProcessCost } from "../node-BTcllpO8.mjs";
|
|
4
|
+
import { C as resolveModelDefaultConfidence, S as landmarkPrecisionVerdict, _ as ALL_STEPS, b as getStepDefinition, f as localFrameRegistry, g as ALL_PIPELINE_STEPS, l as resolveDefaultDetectionModel, n as mergeCustomModels, o as deviceKeyOf, r as buildSubtreeCanRun, s as resolveDeviceEngine, t as CustomModelCatalog, u as macroGateVerdict, v as getDefaultModelForFormat, x as resolveModelForFormat, y as getStep } from "../custom-model-catalog-CtwTRnkw.mjs";
|
|
5
5
|
import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
|
|
6
|
-
import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-
|
|
6
|
+
import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-BZysh_Ow.mjs";
|
|
7
7
|
import * as os$1 from "node:os";
|
|
8
8
|
import * as fs from "node:fs";
|
|
9
9
|
import * as path$1 from "node:path";
|
|
@@ -1214,6 +1214,39 @@ async function terminateChild(proc, graceMs) {
|
|
|
1214
1214
|
}, graceMs);
|
|
1215
1215
|
});
|
|
1216
1216
|
}
|
|
1217
|
+
/**
|
|
1218
|
+
* How long a POISONED worker is given to write its stack after SIGUSR1,
|
|
1219
|
+
* before SIGTERM. `faulthandler` writes from a C signal handler, so a dump
|
|
1220
|
+
* takes milliseconds even while a native call holds the GIL; the bound is
|
|
1221
|
+
* there for the worker that cannot answer at all. Never more than ~2 s: the
|
|
1222
|
+
* recycle it delays is the one that hands the device back to the budget.
|
|
1223
|
+
*/
|
|
1224
|
+
var POOL_STACK_DUMP_WAIT_MS = 1500;
|
|
1225
|
+
/**
|
|
1226
|
+
* Ask a hung worker for every thread's Python stack (SIGUSR1, registered by
|
|
1227
|
+
* the pool with `faulthandler` → its stderr, which the host logs under the
|
|
1228
|
+
* worker label), then wait up to `waitMs` — or until it exits — so the dump
|
|
1229
|
+
* is written before the caller terminates it. Exported for tests.
|
|
1230
|
+
*/
|
|
1231
|
+
async function requestStackDump(proc, waitMs, platform = process.platform) {
|
|
1232
|
+
if (platform === "win32") return "unsupported";
|
|
1233
|
+
if (proc.exitCode !== null || proc.signalCode !== null) return "already-exited";
|
|
1234
|
+
try {
|
|
1235
|
+
proc.kill("SIGUSR1");
|
|
1236
|
+
} catch {
|
|
1237
|
+
return "signal-failed";
|
|
1238
|
+
}
|
|
1239
|
+
await new Promise((resolve) => {
|
|
1240
|
+
const done = () => {
|
|
1241
|
+
clearTimeout(timer);
|
|
1242
|
+
proc.removeListener("exit", done);
|
|
1243
|
+
resolve();
|
|
1244
|
+
};
|
|
1245
|
+
const timer = setTimeout(done, waitMs);
|
|
1246
|
+
proc.once("exit", done);
|
|
1247
|
+
});
|
|
1248
|
+
return "signalled";
|
|
1249
|
+
}
|
|
1217
1250
|
var PoolWorker = class {
|
|
1218
1251
|
process = null;
|
|
1219
1252
|
receiveBuffer = Buffer.alloc(0);
|
|
@@ -2005,7 +2038,30 @@ var PoolWorker = class {
|
|
|
2005
2038
|
if (this.recycling || this.exited || this.process === null) return;
|
|
2006
2039
|
this.recycling = true;
|
|
2007
2040
|
if (this.recycleBackstop) clearTimeout(this.recycleBackstop);
|
|
2008
|
-
|
|
2041
|
+
const proc = this.process;
|
|
2042
|
+
this.dumpStackOfPoisoned(proc).then(() => terminateChild(proc, POOL_WORKER_TERM_GRACE_MS));
|
|
2043
|
+
}
|
|
2044
|
+
/**
|
|
2045
|
+
* Before a POISONED worker is killed, ask it where it hung (SIGUSR1 →
|
|
2046
|
+
* `faulthandler`, bounded by {@link POOL_STACK_DUMP_WAIT_MS}) and say where
|
|
2047
|
+
* the answer went: the worker's stderr, which this host logs line by line as
|
|
2048
|
+
* `[<worker label>] …` warnings just before the exit line. A hang that is
|
|
2049
|
+
* killed without this leaves "it hung" as the whole record.
|
|
2050
|
+
*/
|
|
2051
|
+
async dumpStackOfPoisoned(proc) {
|
|
2052
|
+
if (this.poisonVerdict === null) return;
|
|
2053
|
+
const outcome = await requestStackDump(proc, POOL_STACK_DUMP_WAIT_MS);
|
|
2054
|
+
this.log.warn("poisoned pool worker asked for its stack before SIGTERM", { meta: {
|
|
2055
|
+
worker: this.opts.workerLabel,
|
|
2056
|
+
pid: proc.pid ?? null,
|
|
2057
|
+
runtime: this.opts.poolRuntime,
|
|
2058
|
+
device: this.opts.device ?? "default",
|
|
2059
|
+
reason: this.poisonVerdict.reason,
|
|
2060
|
+
outcome,
|
|
2061
|
+
signal: "SIGUSR1",
|
|
2062
|
+
waitedMs: outcome === "signalled" ? POOL_STACK_DUMP_WAIT_MS : 0,
|
|
2063
|
+
dumpWrittenTo: outcome === "signalled" ? `worker stderr — this log, lines prefixed [${this.opts.workerLabel}]` : "none"
|
|
2064
|
+
} });
|
|
2009
2065
|
}
|
|
2010
2066
|
rejectAll(err) {
|
|
2011
2067
|
const entries = [...this.pending.values()];
|
|
@@ -4352,6 +4408,53 @@ var InferenceDeviceLivenessSupervisor = class {
|
|
|
4352
4408
|
}
|
|
4353
4409
|
};
|
|
4354
4410
|
//#endregion
|
|
4411
|
+
//#region src/detection-pipeline/engine/frame-device-reelection.ts
|
|
4412
|
+
function routeLiveFrameDevice(input) {
|
|
4413
|
+
const requested = input.requestedDeviceKey;
|
|
4414
|
+
if (requested === void 0) return {
|
|
4415
|
+
kind: "as-elected",
|
|
4416
|
+
deviceKey: void 0
|
|
4417
|
+
};
|
|
4418
|
+
const from = input.unusable(requested);
|
|
4419
|
+
if (from === null) return {
|
|
4420
|
+
kind: "as-elected",
|
|
4421
|
+
deviceKey: requested
|
|
4422
|
+
};
|
|
4423
|
+
if (requested === input.defaultDeviceKey || input.unusable(input.defaultDeviceKey) !== null) return {
|
|
4424
|
+
kind: "no-alternative",
|
|
4425
|
+
deviceKey: requested,
|
|
4426
|
+
from
|
|
4427
|
+
};
|
|
4428
|
+
return {
|
|
4429
|
+
kind: "re-elected",
|
|
4430
|
+
deviceKey: void 0,
|
|
4431
|
+
from,
|
|
4432
|
+
to: input.defaultDeviceKey
|
|
4433
|
+
};
|
|
4434
|
+
}
|
|
4435
|
+
/**
|
|
4436
|
+
* Per camera, the routing last said — so a 6 fps camera says "re-elected"
|
|
4437
|
+
* once, not six times a second, and says it again when it is back.
|
|
4438
|
+
*/
|
|
4439
|
+
var FrameReelectionNotes = class {
|
|
4440
|
+
said = /* @__PURE__ */ new Map();
|
|
4441
|
+
note(deviceId, routing) {
|
|
4442
|
+
const previous = this.said.get(deviceId);
|
|
4443
|
+
if (routing.kind === "as-elected") {
|
|
4444
|
+
if (previous === void 0) return null;
|
|
4445
|
+
this.said.delete(deviceId);
|
|
4446
|
+
return routing.deviceKey !== void 0 ? {
|
|
4447
|
+
kind: "restored",
|
|
4448
|
+
deviceKey: routing.deviceKey
|
|
4449
|
+
} : null;
|
|
4450
|
+
}
|
|
4451
|
+
const state = `${routing.kind}|${routing.from.deviceKey}|${routing.from.state}`;
|
|
4452
|
+
if (previous === state) return null;
|
|
4453
|
+
this.said.set(deviceId, state);
|
|
4454
|
+
return routing;
|
|
4455
|
+
}
|
|
4456
|
+
};
|
|
4457
|
+
//#endregion
|
|
4355
4458
|
//#region src/detection-pipeline/engine/pool-memory-guard.ts
|
|
4356
4459
|
function createDetectionPoolMemoryGuard(source, logger) {
|
|
4357
4460
|
const log = logger.child("pool-memory");
|
|
@@ -9722,9 +9825,10 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
9722
9825
|
emit(`Image: ${imageWidth}×${imageHeight}`);
|
|
9723
9826
|
}
|
|
9724
9827
|
decodeMs = performance.now() - decodeT0;
|
|
9828
|
+
const liveDeviceKey = isRuntime && input.replay !== true && input.deviceId !== void 0 && input.sessionId === void 0 ? this.routeLiveFrameDevice(input.deviceKey, input.deviceId) : input.deviceKey;
|
|
9725
9829
|
const dispatchResolution = this.resolveStepsForDispatch({
|
|
9726
9830
|
steps: input.steps,
|
|
9727
|
-
deviceKey:
|
|
9831
|
+
deviceKey: liveDeviceKey,
|
|
9728
9832
|
deviceId: input.deviceId,
|
|
9729
9833
|
plane: input.plane
|
|
9730
9834
|
});
|
|
@@ -10864,6 +10968,49 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
10864
10968
|
* (`encodeModelByte`) that pool could never have served inference again even
|
|
10865
10969
|
* if its worker had come back.
|
|
10866
10970
|
*/
|
|
10971
|
+
/** Per camera, the last live-frame re-election said (see `frame-device-reelection.ts`). */
|
|
10972
|
+
frameReelections = new FrameReelectionNotes();
|
|
10973
|
+
/**
|
|
10974
|
+
* The deviceKey a live frame dispatches on: the elected one while it is
|
|
10975
|
+
* usable, else the node default pool. Each change is said once per camera,
|
|
10976
|
+
* naming the device — a camera whose frames silently moved pool, or were
|
|
10977
|
+
* silently refused, is the failure this exists to end.
|
|
10978
|
+
*/
|
|
10979
|
+
routeLiveFrameDevice(requestedDeviceKey, deviceId) {
|
|
10980
|
+
const routing = routeLiveFrameDevice({
|
|
10981
|
+
requestedDeviceKey,
|
|
10982
|
+
defaultDeviceKey: deviceKeyOf(this.currentEngine),
|
|
10983
|
+
unusable: (key) => this.deviceLiveness.unusableReason(key)
|
|
10984
|
+
});
|
|
10985
|
+
const note = this.frameReelections.note(deviceId, routing);
|
|
10986
|
+
if (note !== null) {
|
|
10987
|
+
const tags = { tags: { deviceId } };
|
|
10988
|
+
if (note.kind === "re-elected") this.log.warn("elected inference device unusable — frames re-elected onto the default pool", {
|
|
10989
|
+
...tags,
|
|
10990
|
+
meta: {
|
|
10991
|
+
deviceKey: note.from.deviceKey,
|
|
10992
|
+
state: note.from.state,
|
|
10993
|
+
deaths: note.from.deaths,
|
|
10994
|
+
lastError: note.from.lastError,
|
|
10995
|
+
reElectedTo: note.to
|
|
10996
|
+
}
|
|
10997
|
+
});
|
|
10998
|
+
else if (note.kind === "no-alternative") this.log.warn("elected inference device unusable and no other pool here — frames refused", {
|
|
10999
|
+
...tags,
|
|
11000
|
+
meta: {
|
|
11001
|
+
deviceKey: note.from.deviceKey,
|
|
11002
|
+
state: note.from.state,
|
|
11003
|
+
deaths: note.from.deaths,
|
|
11004
|
+
lastError: note.from.lastError
|
|
11005
|
+
}
|
|
11006
|
+
});
|
|
11007
|
+
else this.log.info("elected inference device usable again — frames back on it", {
|
|
11008
|
+
...tags,
|
|
11009
|
+
meta: { deviceKey: note.deviceKey }
|
|
11010
|
+
});
|
|
11011
|
+
}
|
|
11012
|
+
return routing.deviceKey;
|
|
11013
|
+
}
|
|
10867
11014
|
refuseIfDeviceUnusable(deviceKey) {
|
|
10868
11015
|
const unhealthy = this.deviceLiveness.unusableReason(deviceKey);
|
|
10869
11016
|
if (unhealthy) throw new InferenceDeviceUnusableError(unhealthy);
|