Skip to content

Commit

Permalink
support config hot reload
Browse files Browse the repository at this point in the history
  • Loading branch information
kfatyuip committed Aug 3, 2024
1 parent 4cdf9de commit fa23757
Show file tree
Hide file tree
Showing 10 changed files with 575 additions and 445 deletions.
31 changes: 31 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ log = ["dep:log"]

[dependencies]
async-mutex = "1.4.0"
async-rwlock = "1.3.0"
chrono = { version = "0.4.38", features = ["clock", "now"] }
clap = { version = "4.5.7", features = ["derive"] }
ipnet = { version = "2.9.0", optional = true }
Expand All @@ -29,6 +30,7 @@ mime = { version = "0.3.17" }
mime_guess = { version = "2.0.4" }
serde = { version = "1.0.203", features = ["derive"] }
serde_yml = "0.0.10"
signal-hook = "0.3.17"
tokio = { version = "1.38.0", features = [
"rt-multi-thread",
"fs",
Expand Down
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,16 @@ logging: # optional
**Benchmark (wrk)**
+ cargo run --release --no-default-features --features=lru_cache -- -p 8080
```text
Running 10s test @ http://localhost:8080/
Running 10s test @ http://localhost:8080
4 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 358.01us 151.88us 2.57ms 72.96%
Req/Sec 3.88k 171.86 5.04k 79.90%
155645 requests in 10.10s, 117.86MB read
Socket errors: connect 0, read 155644, write 0, timeout 0
Requests/sec: 15410.34
Transfer/sec: 11.67MB
wrk http://localhost:8080/ -t 4 -d 10s 1.51s user 11.11s system 124% cpu 10.109 total
Latency 317.11us 168.20us 4.56ms 78.71%
Req/Sec 4.06k 204.86 5.18k 74.19%
162856 requests in 10.10s, 117.10MB read
Socket errors: connect 0, read 162854, write 0, timeout 0
Requests/sec: 16125.32
Transfer/sec: 11.60MB
wrk http://localhost:8080 -t 4 -d 10s 1.59s user 11.45s system 128% cpu 10.110 total
```

+ python -m http.server 8080
Expand Down
2 changes: 1 addition & 1 deletion config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
bind:
addr: 0.0.0.0
listen: 80
listen: 8081

server:
info: "Powered by Rust"
Expand Down
6 changes: 4 additions & 2 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use async_rwlock::RwLock;
use clap::{command, Parser};
use lazy_static::lazy_static;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -98,11 +99,12 @@ pub struct Args {

lazy_static! {
pub static ref CONFIG_PATH: Mutex<String> = Mutex::new("".to_owned());
pub static ref CONFIG: Config = init_config();
pub static ref DEFAULT_CONFIG: Config = init_config();
pub static ref CONFIG: RwLock<Config> = RwLock::new((*DEFAULT_CONFIG).clone());
pub static ref ARGS: Args = Args::parse();
}

fn init_config() -> Config {
pub fn init_config() -> Config {
let config_path = CONFIG_PATH.lock().unwrap();
let default_config = Config::default();
let mut config = match fs::read_to_string(config_path.to_owned()) {
Expand Down
139 changes: 139 additions & 0 deletions src/init.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
use crate::{
config::{init_config, CONFIG},
zest::T,
};
use async_mutex::Mutex;
use lazy_static::lazy_static;
use log4rs::Handle;
use signal_hook::{consts::SIGUSR1, iterator::Signals};
use std::{env::set_current_dir, error::Error};

#[cfg(feature = "log")]
use {
crate::config::Config,
log4rs::{
append::{console::ConsoleAppender, file::FileAppender},
config::{Appender, Logger, Root},
encode::pattern::PatternEncoder,
},
std::{ops::Deref, path::Path},
};

#[cfg(feature = "log")]
const LOG_FORMAT: &str = "[{d(%Y-%m-%dT%H:%M:%SZ)} {h({l})} zest] {m}\n";

lazy_static! {
pub static ref LOGGER_HANDLE: Mutex<Option<Handle>> = Mutex::new(None);
}

#[cfg(feature = "log")]
pub async fn build_logger_config<C>(config: C) -> log4rs::Config
where
C: Deref<Target = Config>,
{
let mut builder = log4rs::Config::builder();

let stdout = ConsoleAppender::builder()
.encoder(Box::new(PatternEncoder::new(LOG_FORMAT)))
.target(log4rs::append::console::Target::Stdout)
.build();

let stderr = ConsoleAppender::builder()
.encoder(Box::new(PatternEncoder::new(LOG_FORMAT)))
.target(log4rs::append::console::Target::Stderr)
.build();

let logging = &config.logging.clone().unwrap_or_default();
builder = if let Some(access_log) = &logging.access_log {
let access_log_path = Path::new(&access_log);
std::fs::File::create(access_log_path).unwrap();
builder.appender(
Appender::builder().build(
"logfile_access",
Box::new(
FileAppender::builder()
.encoder(Box::new(PatternEncoder::new(LOG_FORMAT)))
.build(access_log_path)
.unwrap(),
),
),
)
} else {
builder.appender(Appender::builder().build("logfile_access", Box::new(stdout)))
};

builder = if let Some(error_log) = &logging.error_log {
let error_log_path = Path::new(&error_log);
std::fs::File::create(error_log_path).unwrap();
builder.appender(
Appender::builder().build(
"logfile_error",
Box::new(
FileAppender::builder()
.encoder(Box::new(PatternEncoder::new(LOG_FORMAT)))
.build(error_log_path)
.unwrap(),
),
),
)
} else {
builder.appender(Appender::builder().build("logfile_error", Box::new(stderr)))
};

builder
.logger(
Logger::builder()
.appender("logfile_access")
.additive(false)
.build("access", log::LevelFilter::Info),
)
.logger(
Logger::builder()
.appender("logfile_error")
.additive(false)
.build("error", log::LevelFilter::Error),
)
.build(Root::builder().build(log::LevelFilter::Off))
.unwrap()
}

#[cfg(feature = "log")]
pub async fn init_logger<C>(config: C)
where
C: Deref<Target = Config>,
{
let config = build_logger_config(config).await;
*LOGGER_HANDLE.lock().await = Some(log4rs::init_config(config).unwrap())
}

pub async fn init_signal() -> Result<(), Box<dyn Error>> {
let mut signals = Signals::new([SIGUSR1])?;

tokio::spawn(async move {
for sig in signals.forever() {
if sig == SIGUSR1 {
let config: crate::config::Config = init_config();

let mut _c = CONFIG.try_write().unwrap();
*_c = config.clone();
drop(_c);

set_current_dir(config.clone().server.root).unwrap();

#[cfg(feature = "log")]
{
let mut _handle = LOGGER_HANDLE.lock().await;
if let Some(handle) = _handle.take() {
handle.set_config(build_logger_config(&config.clone()).await);
}
}

let mut t = T.try_write().unwrap();
*t = None;
drop(t);
}
}
});

Ok(())
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
pub mod config;
pub mod init;
pub mod route;
pub mod zest;

#[cfg(test)]
mod tests {
Expand Down
Loading

0 comments on commit fa23757

Please sign in to comment.