Node Hooks
Node hooks fire when a runner starts and finishes executing a node, or when a node encounters an error.
Methods
fn before_node_run(&self, n: &dyn PipelineInfo) {}
fn after_node_run(&self, n: &dyn PipelineInfo) {}
fn on_node_error(&self, n: &dyn PipelineInfo, error: &str) {}
Arguments
n— the node being executed. Usen.name()for the node name,n.type_string()for the function’s type name.error(onon_node_error) — the stringified error message. Instdbuilds this ise.to_string(); inno_stdit’s the fixed string"node error".
Lifecycle
For a successful node execution:
before_node_run(n)
before_dataset_loaded(n, ds0)
after_dataset_loaded(n, ds0)
... (function executes) ...
before_dataset_saved(n, ds_out)
after_dataset_saved(n, ds_out)
after_node_run(n)
For a failed node:
before_node_run(n)
... (error occurs during load, function, or save) ...
on_node_error(n, "error message")
after_node_run and on_node_error are mutually exclusive — exactly one fires per node execution.
Example: counting nodes
use std::sync::atomic::{AtomicUsize, Ordering};
struct NodeCounter {
count: AtomicUsize,
}
impl Hook for NodeCounter {
fn after_node_run(&self, n: &dyn PipelineInfo) {
let i = self.count.fetch_add(1, Ordering::Relaxed) + 1;
println!("Completed node {} ({}/total)", n.name(), i);
}
fn on_node_error(&self, n: &dyn PipelineInfo, error: &str) {
eprintln!("Node {} failed: {}", n.name(), error);
}
}
Parallel runner behavior
With the ParallelRunner, node hooks may fire from different threads concurrently. This is why Hook: Sync is required. Use atomic types or Mutex for any shared state in your hook.