#config-file #hot-reloading #traits #reload #periodic #async #periodically

hot_reload

Trait and service definition of periodic hot reloader and notifier for config-file, KVS, etc

6 releases

0.1.5 Jan 23, 2024
0.1.4 Jul 21, 2023

#405 in Filesystem

Download history 11/week @ 2023-12-22 13/week @ 2023-12-29 30/week @ 2024-01-05 42/week @ 2024-01-12 143/week @ 2024-01-19 45/week @ 2024-01-26 13/week @ 2024-02-02 85/week @ 2024-02-09 17/week @ 2024-02-16 26/week @ 2024-02-23 26/week @ 2024-03-01 32/week @ 2024-03-08 32/week @ 2024-03-15 5/week @ 2024-03-29 82/week @ 2024-04-05

125 downloads per month

MIT license

10KB
125 lines

Periodic hot reloader and notifier for files, KVS, etc. for Rust

hot_reload hot_reload License: MIT

This provides a Rust trait definition and service library for hot-reloading your files, KVS, etc. by periodically checking the system.

Reload Trait Definition

To use this library, you need to prepare your own struct implementing reloader::Reload trait, defined as follows:

#[async_trait]
/// Trait defining the responsibility of reloaders to periodically load the target value `V` from `Source`.
/// Source could be a file, a KVS, whatever if you can implement `Reload<V>` with `Reload<V>::Source`.
pub trait Reload<V>
where
  V: Eq + PartialEq
{
  type Source;
  async fn new(src: &Self::Source) -> Result<Self, ReloaderError<V>>
  where
    Self: Sized;
  async fn reload(&self) -> Result<Option<V>, ReloaderError<V>>;
}

This trait defines the source type (file, KVS, etc) and reloaded object type V. The following is an example of periodic-reloading a config-file through a given file path string.

pub struct ConfigReloader {
  pub config_path: PathBuf,
}

#[async_trait]
impl Reload<ServerConfig> for ConfigReloader {
  type Source = String;
  async fn new(source: &Self::Source) -> Result<Self, ReloaderError<ServerConfig>> {
    Ok(Self {
      config_path: PathBuf::from(source),
    })
  }

  async fn reload(&self) -> Result<Option<ServerConfig>, ReloaderError<ServerConfig>> {
    let config_str = std::fs::read_to_string(&self.config_path).context("Failed to read config file")?;
    let config: ServerConfig = config_object_from_str(config_str);

    Ok(Some(config))
  }
}

Usage

use hot_reload::*;

let (reloader, rx) = ReloaderService::new(source, 10, false).await.unwrap();
tokio::spawn(async move { reloader_service.start().await });
loop {
  tokio::select! {
    // Add main logic of the event loop with up-to-date value
    _ = something.happened() => {
      // ...
    }
    // immediately update if watcher detects the change
    _ = rx.changed()  => {
      if rx.borrow().is_none() {
        break;
      }
      let value = rx.borrow().clone();
      info!("Received value via watcher");
      info!("value: {:?}", value.unwrap().clone());
    }
    else => break
    }
  }
}

Dependencies

~2.7–4.5MB
~73K SLoC