85 lines
2.6 KiB
Markdown
85 lines
2.6 KiB
Markdown
# 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"
|
|
```
|