#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

#406 in Filesystem

Download history 151/week @ 2024-01-17 29/week @ 2024-01-24 40/week @ 2024-01-31 15/week @ 2024-02-07 80/week @ 2024-02-14 22/week @ 2024-02-21 28/week @ 2024-02-28 33/week @ 2024-03-06 40/week @ 2024-03-13 3/week @ 2024-03-27 8/week @ 2024-04-03 86/week @ 2024-04-10 1/week @ 2024-04-17 50/week @ 2024-04-24 1/week @ 2024-05-01

138 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
~72K SLoC