Hot reload
Hot reload swaps route pipelines at runtime without stopping the context. When a route file changes on disk, the runtime compiles the new pipeline and swaps it atomically. In-flight exchanges complete against the pipeline snapshot they entered.
Architecture
The runtime stores the active pipeline behind ArcSwap. A swap
publishes a new Arc in one atomic step. New exchanges see the new
pipeline immediately. Exchanges already in flight hold their existing
Arc and finish against the old pipeline. Old and new pipelines coexist
until the last in-flight exchange drains.
Reference: ADR-0004
Configuration
Set watch_debounce_ms in Camel.toml to control the debounce delay.
The watcher waits this long after the last file event before it reloads.
Increase the value if one save triggers several rapid reloads.
[default]
routes = ["routes/**/*.yaml"]
log_level = "INFO"
# Debounce delay for the file watcher (milliseconds).
# Increase if you see multiple rapid reloads on a single save.
watch_debounce_ms = 300
Usage
Load the debounce from config
The hot-reload-yaml example reads watch_debounce_ms from Camel.toml
and passes it to watch_and_reload.
// ── 0. Load configuration (watch_debounce_ms etc.) ───────────────────────
// Falls back to the CamelConfig field default (300 ms) if Camel.toml is absent.
let debounce_ms = CamelConfig::from_file("Camel.toml")
.map(|c| c.watch_debounce_ms)
.unwrap_or(300);
println!("[0] watch_debounce_ms = {debounce_ms} ms (set in Camel.toml)");
Start the watcher
The hot-reload example resolves the directories to watch, then starts
watch_and_reload in a background task. A CancellationToken stops the
watcher on shutdown.
tokio::spawn(async move {
let watch_dirs = resolve_watch_dirs(&watch_patterns);
let result = watch_and_reload(
watch_dirs,
ctrl,
move || {
camel_dsl::discover_routes(&watch_patterns)
.map_err(|e| CamelError::RouteError(e.to_string()))
},
Some(shutdown_watcher),
std::time::Duration::from_secs(10),
std::time::Duration::from_millis(300),
)
.await;
The watched route file uses a plain YAML route:
- from: timer:hot-reload?period=1000
route_id: hot-reload-route
steps:
- to: log:info?showHeaders=true
How it works
- The file watcher monitors route directories for changes.
- After the debounce window, it calls
discover_routesto reload route definitions. - It computes reload actions (swap, add, remove) by comparing the old and new routes.
- It applies each action on the runtime controller.
The watcher runs in a background task. Pass a CancellationToken to stop
it on shutdown.
When to use
Use hot reload for zero-downtime updates. Edit a route, save the file, and the running context adopts the change within the debounce window. This fits long-running integration services that cannot restart during traffic. Do not use hot reload where route correctness needs a full compile-time check. Prefer the Rust builder API and a redeploy for that case.
Reference: reload_watcher::watch_and_reload in the Runtime crate