#hot-reloading #config-file #async-trait #periodic #reload #source #source-file

hot_reload

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

9 releases

0.1.8 Nov 5, 2024
0.1.7 Nov 5, 2024
0.1.6 Jul 16, 2024
0.1.5 Jan 23, 2024
0.1.4 Jul 21, 2023

#438 in Filesystem

Download history 74/week @ 2024-07-29 14/week @ 2024-08-05 24/week @ 2024-08-19 46/week @ 2024-08-26 125/week @ 2024-09-02 118/week @ 2024-09-09 105/week @ 2024-09-16 64/week @ 2024-09-23 31/week @ 2024-09-30 103/week @ 2024-10-07 29/week @ 2024-10-14 46/week @ 2024-10-21 136/week @ 2024-10-28 344/week @ 2024-11-04 28/week @ 2024-11-11

556 downloads per month

MIT license

11KB
140 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.6–8.5MB
~71K SLoC