// Example 15 — Per-node Error Handler // // Demonstrates set_error_handler() for deciding whether a network can // continue when a node throws an exception. // // The "validator" node rejects even numbers by throwing std::runtime_error. // Its error handler logs the failure and returns true (skip & continue), // so odd numbers still flow through to the sink. // // Compare: a second handler (commented below) returns false instead, // which stops the node and gracefully shuts the downstream side down. // // Pipeline: [source] --int--> [validator] --int--> [sink] #include #include #include #include static int counter = 0; static int source() { std::this_thread::sleep_for(std::chrono::milliseconds(20)); return ++counter; } static int validate(int x) { if (x % 2 == 0) throw std::runtime_error("even number rejected: " + std::to_string(x)); return x; } static int received = 0; static void sink(int x) { std::cout << " processed: " << x << '\n'; ++received; } int main() { using namespace kpn; auto src = make_node (); auto proc = make_node(); auto snk = make_node (); // --8<-- [start:error_handler] // Return true → skip this invocation, keep the node running. // Return false → stop the node (downstream drains then also stops). proc.set_error_handler([](std::string_view name, std::exception_ptr ep) { try { std::rethrow_exception(ep); } catch (const std::exception& e) { std::cerr << "[" << name << "] skipping item — " << e.what() << '\n'; } return true; }); // --8<-- [end:error_handler] Network net; net.add("source", src) .add("validator", proc) .add("sink", snk) .connect("source", src.output<0>(), "validator", proc.input<0>()) .connect("validator", proc.output<0>(), "sink", snk.input<0>()) .build(); std::cout << "source emits 1..N; validator rejects even numbers.\n" << "Error messages on stderr, accepted items on stdout.\n\n"; net.start(); std::this_thread::sleep_for(std::chrono::milliseconds(300)); net.stop(); std::cout << "\nItems accepted by sink: " << received << '\n'; }