Hot reloading
Compiling a Unit
and a [RuntimeContext
] are expensive operations compared
to the cost of calling a function. So you should try to do this as little as
possible. It is appropriate to recompile a script when the source of the script
changes. This section provides you with details for how this can be done when
loading scripts from the filesystem.
A typical way to accomplish this is to watch a scripts directory using the
notify
crate. This allow the application to generate events whenever changes
to the directory are detected. See the hot_reloading
example and in
particular the PathReloader
type.
#[path = "hot_reloading/path_reloader.rs"] mod path_reloader; use std::path::PathBuf; use std::pin::pin; use std::sync::Arc; use anyhow::{Context as _, Result}; use rune::{Context, Vm}; #[tokio::main(flavor = "current_thread")] async fn main() -> Result<()> { let root = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").context("missing CARGO_MANIFEST_DIR")?); let context = Context::with_default_modules()?; let mut exit = pin!(tokio::signal::ctrl_c()); let mut reloader = pin!(path_reloader::PathReloader::new( root.join("scripts"), &context )?); let context = Arc::new(context.runtime()?); let mut events = Vec::new(); loop { tokio::select! { _ = exit.as_mut() => { break; } result = reloader.as_mut().watch(&mut events) => { result?; } } for event in events.drain(..) { let mut vm = Vm::new(context.clone(), event.unit); match event.kind { path_reloader::EventKind::Added => { if let Err(error) = vm.call(["hello"], ()) { println!("Error: {}", error); } } path_reloader::EventKind::Removed => { if let Err(error) = vm.call(["goodbye"], ()) { println!("Error: {}", error); } } } } } Ok(()) }