// Example 05 — Error Handling & Diagnostics // // Demonstrates observable failure modes and the diagnostics system: // // 1. ChannelOverflowError — a fast producer saturates a slow consumer. // When the channel is full, push() throws ChannelOverflowError. // The node's run_loop catches it and prints to stderr. // Channel statistics (overflows, peak fill) accumulate for the report. // // 2. Custom diagnostics handler — instead of the default periodic table, // install a handler that surfaces only the metrics you care about. // // 3. net.print_diagnostics() — print a full report at any time. // // Pipeline: [producer] --int--> [slow_consumer] #include #include #include #include // ── Node functions ──────────────────────────────────────────────────────────── // Produces at ~100/s — faster than the consumer can keep up (50 ms each) static int producer() { std::this_thread::sleep_for(std::chrono::milliseconds(10)); static int n = 0; return ++n; } // Slow consumer: 50 ms per item — will cause channel to fill and overflow static void slow_consumer(int x) { std::this_thread::sleep_for(std::chrono::milliseconds(50)); std::cout << "[consumed] " << x << '\n'; } // ── main ────────────────────────────────────────────────────────────────────── int main() { using namespace kpn; // Capacity=4: fills up quickly when producer outpaces consumer 5:1 auto prod = make_node (out<"v">{}, /*capacity=*/4); auto cons = make_node (in<"v">{}, /*capacity=*/4); Network net; // --8<-- [start:diagnostics_handler] // Custom diagnostics handler — fires on the watchdog interval. // Print a concise one-liner rather than the full table. net.set_diagnostics_handler([](const std::vector& nodes, const std::vector& channels) { std::cout << "[diag] "; for (auto& n : nodes) std::cout << n.name << "=" << n.throughput_fps << "fps "; for (auto& c : channels) std::cout << "channel fill=" << static_cast(c.fill_pct()) << "% " << "overflows=" << c.overflows; std::cout << '\n'; }); // --8<-- [end:diagnostics_handler] net.set_watchdog_interval(std::chrono::milliseconds(200)); net.add("prod", prod) .add("cons", cons) .connect("prod", prod.template output<"v">(), "cons", cons.template input<"v">()) .build(); std::cout << "producer: 10ms/item, consumer: 50ms/item, capacity=4\n" << "Overflow messages appear on stderr; diagnostics on stdout.\n\n"; net.start(); std::this_thread::sleep_for(std::chrono::milliseconds(800)); net.stop(); // Full report after shutdown — overflow and drop counts are preserved std::cout << '\n'; net.print_diagnostics(); }