//! Hot reload support for the GIngress proxy. //! //! Watches the `ConfigStore` reload channel and gracefully applies //! configuration changes without dropping active connections. use crate::config::ConfigStore; /// Hot-reload watcher that listens for config changes. pub struct HotReloadWatcher { store: ConfigStore, current_version: u64, } impl HotReloadWatcher { pub fn new(store: ConfigStore) -> Self { Self { store, current_version: 0, } } /// Wait for the next configuration change. /// Returns true if config changed, false if the channel was closed. pub async fn wait_for_change(&mut self) -> bool { let mut rx = self.store.reload_rx(); loop { match rx.changed().await { Ok(()) => { let new_version = *rx.borrow(); if new_version != self.current_version { self.current_version = new_version; return true; } } Err(_) => return false, } } } /// Get the current configuration snapshot. pub fn store(&self) -> &ConfigStore { &self.store } } /// Spawn a background task that watches for config changes and applies them. /// /// The `on_reload` callback is invoked each time the config changes. pub fn spawn_reload_watcher(store: ConfigStore, on_reload: F) -> tokio::task::JoinHandle<()> where F: Fn(&ConfigStore) + Send + 'static, { tokio::spawn(async move { let mut watcher = HotReloadWatcher::new(store); loop { if !watcher.wait_for_change().await { tracing::info!("Config reload channel closed, stopping watcher"); break; } tracing::info!("Config change detected, reloading..."); on_reload(watcher.store()); } }) }