fix(kpn): park on full outputs; surface node exceptions
Adopts the KPN backpressure fix (28e0667) and registers the application error listener it exposes. `push_blocking` parked a scheduler worker inside the push. Each ObjectNode owns a private single-thread pool, so the parked thread was the only one that could drain that node's own input: under sustained backpressure frame_source, camera_pos, face_detector and face_aligner all slept in nanosleep at once and the pipeline stopped. Nodes now hold the value, release the worker, and resume on a channel space-callback. main.cpp registers set_error_handler so a node that throws names itself and its exception. Previously the exception was discarded at the node boundary and survived only as "node 'x' stopped unexpectedly", which says that a node died but not why — the missing detail that made this slow to diagnose. AR-004 drops from Done to Mostly. Two gaps are recorded rather than claimed fixed: a hang surviving at roughly 1 run in 20 against a 300 s timeout (down from every run failing), and FanoutNode still dropping on overflow instead of parking, which sheds frames on the AR-010 scene join precisely when the dense branch falls behind. TRACES: AR-004 | SR-002
This commit is contained in:
+24
-4
@@ -39,8 +39,8 @@
|
||||
// --max-faces <N> max faces kept per frame (default: 10)
|
||||
// --expand-gallery enable per-film gallery expansion from track continuity
|
||||
// --expand-buffer <N> per-track diversity buffer size (default: 20)
|
||||
// --expand-novelty-sim <f> promote only views with best sim < f (default: 0.55)
|
||||
// --expand-spread-max <f> reject track if buffer spread > f (default: 0.60)
|
||||
// --expand-band-lo <p> store admission floor, P(same person) (default: 0.90)
|
||||
// --expand-band-hi <p> store admission ceiling, P(same person) (default: 0.95)
|
||||
// --expand-min-anchor <N> accepted frames before a track confirms (default: 3)
|
||||
// --expand-debug-dir <p> dump promoted mugshots + embeddings here (SAE_DEBUG)
|
||||
// (SAE_DEBUG only)
|
||||
@@ -147,8 +147,8 @@ static Config parse_args(int argc, char** argv) {
|
||||
else if (arg("--anneal")) cfg.anneal_sec = std::stod(next());
|
||||
else if (arg("--expand-gallery")) cfg.expand_gallery = true;
|
||||
else if (arg("--expand-buffer")) cfg.expand_buffer_size = std::stoi(next());
|
||||
else if (arg("--expand-novelty-sim")) cfg.expand_novelty_sim = std::stof(next());
|
||||
else if (arg("--expand-spread-max")) cfg.expand_track_spread_max = std::stof(next());
|
||||
else if (arg("--expand-band-lo")) cfg.expand_band_lo = std::stof(next());
|
||||
else if (arg("--expand-band-hi")) cfg.expand_band_hi = std::stof(next());
|
||||
else if (arg("--expand-min-anchor")) cfg.expand_min_anchor_frames = std::stoi(next());
|
||||
else if (arg("--expand-debug-dir")) cfg.expand_debug_dir = next();
|
||||
else if (arg("--trt-cache")) cfg.trt.cache_dir = next();
|
||||
@@ -281,6 +281,26 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
});
|
||||
|
||||
// Report *why* a node died. A Closed event alone says only that one
|
||||
// stopped; the exception it carried is what identifies the fault, and
|
||||
// without this listener it is discarded at the node boundary. Returning
|
||||
// false keeps the existing semantics — the node still stops and the
|
||||
// Closed handler above still aborts the run — but the run now names the
|
||||
// cause instead of leaving it to be reconstructed from a debugger.
|
||||
net.set_error_handler(
|
||||
[&](std::string_view node_name, std::exception_ptr eptr) {
|
||||
std::string what = "unknown exception";
|
||||
try {
|
||||
if (eptr) std::rethrow_exception(eptr);
|
||||
} catch (const std::exception& e) {
|
||||
what = e.what();
|
||||
} catch (...) {
|
||||
}
|
||||
std::lock_guard<std::mutex> lk(event_mtx);
|
||||
std::cerr << "[main] node '" << node_name << "' threw: " << what << "\n";
|
||||
return false;
|
||||
});
|
||||
|
||||
std::cerr << "[main] starting pipeline…\n";
|
||||
net.start();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user