chore: phase 1 cleanup — proper shutdown, flow resource cleanup, test fix

- node_runner: track all readers/writers in flow_resources vector,
  release them via mxlReleaseFlowWriter/mxlReleaseFlowReader before
  destroying the MXL instance (fixes 'leaked flow writer' warning)
- node_runner: remove_writer/remove_reader commands now also release
  the MXL flow resources, not just reset the node's optional<>
- engine: call process_manager.stop_all(graph) on shutdown to kill
  child node processes (prevents orphaned passthrough processes)
- graph: add get_node_mut() for process_manager to update node state
- process_manager: implement stop_all(Graph&) that SIGTERMs all
  running node processes
- passthrough: reduce logging to first-grain and realign-once only
- tests: update flow format assertion to match NMOS
  (urn:x-nmos:format:video instead of video/v210)
This commit is contained in:
Johanness
2026-05-26 23:04:16 +03:00
parent 5b48d86c6e
commit 4b50f49172
8 changed files with 68 additions and 9 deletions
+35 -1
View File
@@ -94,7 +94,14 @@ int NodeRunner::exec(std::unique_ptr<Node> node) {
return arr;
};
control_server->register_command("add_writer", [&, w = std::unordered_map<std::string, mxlFlowWriter>{}](const nlohmann::json& msg) mutable {
struct FlowResource {
std::string port_id;
mxlFlowWriter writer = nullptr;
mxlFlowReader reader = nullptr;
};
std::vector<FlowResource> flow_resources;
control_server->register_command("add_writer", [&](const nlohmann::json& msg) {
auto flow_id = msg["flow_id"].get<std::string>();
auto port_id = msg["port_id"].get<std::string>();
auto flow_def = msg["flow_def"].dump();
@@ -108,6 +115,7 @@ int NodeRunner::exec(std::unique_ptr<Node> node) {
return;
}
spdlog::info("Created flow writer on port '{}' flow {} (created={})", port_id, flow_id, created);
flow_resources.push_back({port_id, writer, nullptr});
node->on_add_writer(port_id, writer);
});
@@ -122,18 +130,33 @@ int NodeRunner::exec(std::unique_ptr<Node> node) {
return;
}
spdlog::info("Created flow reader on port '{}' flow {}", port_id, flow_id);
flow_resources.push_back({port_id, nullptr, reader});
node->on_add_reader(port_id, reader);
});
control_server->register_command("remove_writer", [&](const nlohmann::json& msg) {
auto port_id = msg["port_id"].get<std::string>();
node->on_remove_writer(port_id);
for (auto it = flow_resources.begin(); it != flow_resources.end(); ++it) {
if (it->port_id == port_id && it->writer) {
mxlReleaseFlowWriter(mxl_instance_, it->writer);
flow_resources.erase(it);
break;
}
}
spdlog::info("Removed writer on port '{}'", port_id);
});
control_server->register_command("remove_reader", [&](const nlohmann::json& msg) {
auto port_id = msg["port_id"].get<std::string>();
node->on_remove_reader(port_id);
for (auto it = flow_resources.begin(); it != flow_resources.end(); ++it) {
if (it->port_id == port_id && it->reader) {
mxlReleaseFlowReader(mxl_instance_, it->reader);
flow_resources.erase(it);
break;
}
}
spdlog::info("Removed reader on port '{}'", port_id);
});
@@ -184,6 +207,17 @@ int NodeRunner::exec(std::unique_ptr<Node> node) {
process_thread.join();
spdlog::info("Node '{}' shutting down", node_id_);
for (auto& res : flow_resources) {
if (res.writer) {
mxlReleaseFlowWriter(mxl_instance_, res.writer);
}
if (res.reader) {
mxlReleaseFlowReader(mxl_instance_, res.reader);
}
}
flow_resources.clear();
mxlDestroyInstance(mxl_instance_);
return 0;
}