use std::sync::{Arc, OnceLock};
use tokio::runtime::{Builder, Runtime};
static SHARED_RUNTIME: OnceLock<Arc<Runtime>> = OnceLock::new();
pub fn shared_runtime() -> Arc<Runtime> {
SHARED_RUNTIME
.get_or_init(|| {
Arc::new(
Builder::new_multi_thread()
.worker_threads(get_cpu_count())
.thread_name("hojicha-async")
.enable_all()
.build()
.expect("Failed to create Tokio runtime"),
)
})
.clone()
}
#[derive(Debug, Clone)]
pub struct RuntimeConfig {
pub worker_threads: Option<usize>,
pub thread_name_prefix: String,
pub enable_io: bool,
pub enable_time: bool,
}
impl Default for RuntimeConfig {
fn default() -> Self {
Self {
worker_threads: None,
thread_name_prefix: "hojicha-async".to_string(),
enable_io: true,
enable_time: true,
}
}
}
pub fn initialize_runtime(config: RuntimeConfig) -> Result<(), std::io::Error> {
if SHARED_RUNTIME.get().is_some() {
return Ok(()); }
let mut builder = Builder::new_multi_thread();
if let Some(threads) = config.worker_threads {
builder.worker_threads(threads);
} else {
builder.worker_threads(get_cpu_count());
}
builder.thread_name(&config.thread_name_prefix);
if config.enable_io && config.enable_time {
builder.enable_all();
} else {
if config.enable_io {
builder.enable_io();
}
if config.enable_time {
builder.enable_time();
}
}
let runtime = Arc::new(builder.build()?);
let _ = SHARED_RUNTIME.set(runtime);
Ok(())
}
fn get_cpu_count() -> usize {
std::thread::available_parallelism()
.map(|n| n.get())
.unwrap_or(4)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_shared_runtime_singleton() {
let rt1 = shared_runtime();
let rt2 = shared_runtime();
assert!(Arc::ptr_eq(&rt1, &rt2));
}
}