# Error Handling & Events KPN++ provides three complementary layers for observing and reacting to failures. --- ## 1. Per-node error handler Called when a node's function throws an unhandled exception. Return `true` to skip the failed invocation and keep running; `false` to stop the node. ```cpp --8<-- "examples/15_node_error_handler/main.cpp:error_handler" ``` When a node stops (either from `false` return or no handler installed), it: 1. Disables its **input** channels — upstream stops pushing into dead queues. 2. Disables its **output** channels — downstream nodes receive `ChannelClosedError` on their next pop, propagating the shutdown naturally through the graph. --- ## 2. Per-node overflow callback Fired with a timestamp each time an output push is dropped because the channel is full. The node name is known at registration so it is not included — keeping the callback zero-overhead when unused. ```cpp --8<-- "examples/16_event_callbacks/main.cpp:per_node_callback" ``` !!! note The callback is purely informational — the node always continues after an overflow. To stop the node on overflow, call `node.stop()` from inside the callback. A matching `set_closed_callback()` fires (also with just a timestamp) when the node stops due to a closed upstream channel: ```cpp node.set_closed_callback([](std::chrono::steady_clock::time_point ts) { std::cerr << "node stopped at t=" << ts.time_since_epoch().count() << '\n'; }); ``` Each node holds two callback slots per event type — one user-set (registered above) and one injected by the network (see below). Both fire independently. --- ## 3. Network-level event handler One callback for the whole network. Receives the node name (captured in a closure by the network at `build()` / `start()`), a `NodeEvent`, and a timestamp: ```cpp --8<-- "examples/16_event_callbacks/main.cpp:network_event_handler" ``` `NodeEvent` values: | Value | Meaning | |---|---| | `NodeEvent::Overflow` | An output push was dropped (channel full) | | `NodeEvent::Closed` | The node stopped (crash or upstream close cascade) | The network handler and any per-node callbacks are **independent** — both fire when set. --- ## Complete example `examples/16_event_callbacks/main.cpp` shows a fast producer overflowing a slow consumer, with both a per-node overflow callback and a network-level event handler active simultaneously. Node functions: ```cpp --8<-- "examples/16_event_callbacks/main.cpp:node_fns" ``` Per-node overflow callback: ```cpp --8<-- "examples/16_event_callbacks/main.cpp:per_node_callback" ``` Network-level event handler: ```cpp --8<-- "examples/16_event_callbacks/main.cpp:network_event_handler" ```