From b9fa2bf3fbb26bb98d6b4e671a9233a3ae71aecd Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Tue, 7 Mar 2023 00:40:56 -0800 Subject: [PATCH] feat: add support for `--max-blocking-threads` (#181) * Updated the web server with the latest fixes for blocking and race conditions * Improve default values based on feedback * Fix code formatting --------- Co-authored-by: Johnathan Sharratt Co-authored-by: Jose Quintana --- docs/content/configuration/command-line-arguments.md | 3 +++ docs/content/configuration/environment-variables.md | 3 +++ src/server.rs | 25 +++++++++++++++++++------ src/settings/cli.rs | 43 ++++++++++++++++++++++++++++++++++++++----- src/settings/file.rs | 2 ++ src/settings/mod.rs | 5 +++++ 6 files changed, 70 insertions(+), 11 deletions(-) diff --git a/docs/content/configuration/command-line-arguments.md b/docs/content/configuration/command-line-arguments.md index a3a4df1..64700df 100644 --- a/docs/content/configuration/command-line-arguments.md +++ b/docs/content/configuration/command-line-arguments.md @@ -119,6 +119,9 @@ OPTIONS: or 1 then one thread per core is used. Number of worker threads result should be a number between 1 and 32,768 though it is advised to keep this value on the smaller side [env: SERVER_THREADS_MULTIPLIER=] [default: 1] + -b, --max_blocking_threads + Maximum number of blocking threads + [default: 512] ``` ## Windows diff --git a/docs/content/configuration/environment-variables.md b/docs/content/configuration/environment-variables.md index 0263627..65c954c 100644 --- a/docs/content/configuration/environment-variables.md +++ b/docs/content/configuration/environment-variables.md @@ -42,6 +42,9 @@ HTML file path that is used for `GET` requests when the requested path doesn't e ### SERVER_THREADS_MULTIPLIER The number of worker threads multiplier that'll be multiplied by the number of system CPUs using the formula: `worker threads = number of CPUs * n` where `n` is the value that changes here. When the multiplier value is 0 or 1 then the `number of CPUs` is used. The number of worker threads result should be a number between 1 and 32,768 though it is advised to keep this value on the smaller side. Default one thread per core. +### SERVER_MAX_BLOCKING_THREADS +Maximum number of blocking threads. + ### SERVER_HTTP2_TLS Enable HTTP/2 with TLS support. Make sure also to adjust the current server port. Default `false` (disabled). diff --git a/src/server.rs b/src/server.rs index 3fb66bf..ef19deb 100644 --- a/src/server.rs +++ b/src/server.rs @@ -18,7 +18,8 @@ use crate::{service::RouterService, Context, Result}; /// Define a multi-thread HTTP or HTTP/2 web server. pub struct Server { opts: Settings, - threads: usize, + worker_threads: usize, + max_blocking_threads: usize, } impl Server { @@ -29,12 +30,17 @@ impl Server { // Configure number of worker threads let cpus = num_cpus::get(); - let threads = match opts.general.threads_multiplier { + let worker_threads = match opts.general.threads_multiplier { 0 | 1 => cpus, n => cpus * n, }; + let max_blocking_threads = opts.general.max_blocking_threads; - Ok(Server { opts, threads }) + Ok(Server { + opts, + worker_threads, + max_blocking_threads, + }) } /// Build and run the multi-thread `Server` as standalone. @@ -59,10 +65,11 @@ impl Server { where F: FnOnce(), { - tracing::debug!("initializing tokio runtime with multi thread scheduler"); + tracing::debug!(%self.worker_threads, "initializing tokio runtime with multi thread scheduler"); tokio::runtime::Builder::new_multi_thread() - .worker_threads(self.threads) + .worker_threads(self.worker_threads) + .max_blocking_threads(self.max_blocking_threads) .thread_name("static-web-server") .enable_all() .build()? @@ -135,9 +142,15 @@ impl Server { let page_fallback = helpers::read_bytes_default(&general.page_fallback.unwrap_or_default()); // Number of worker threads option - let threads = self.threads; + let threads = self.worker_threads; tracing::info!("runtime worker threads: {}", threads); + // Maximum number of blocking threads + tracing::info!( + "runtime max blocking threads: {}", + general.max_blocking_threads + ); + // Security Headers option let security_headers = general.security_headers; tracing::info!("security headers: enabled={}", security_headers); diff --git a/src/settings/cli.rs b/src/settings/cli.rs index 9b541c1..166c9c5 100644 --- a/src/settings/cli.rs +++ b/src/settings/cli.rs @@ -32,18 +32,51 @@ pub struct General { /// static-web-server to be sandboxed more completely. pub fd: Option, - #[structopt( - long, - short = "n", - default_value = "1", - env = "SERVER_THREADS_MULTIPLIER" + #[cfg_attr( + not(wasm), + structopt( + long, + short = "n", + default_value = "1", + env = "SERVER_THREADS_MULTIPLIER" + ) )] + #[cfg_attr( + wasm, + structopt( + long, + short = "n", + default_value = "2", + env = "SERVER_THREADS_MULTIPLIER" + ) + )] // We use 2 as the threads multiplier in Wasm, 1 in Native /// Number of worker threads multiplier that'll be multiplied by the number of system CPUs /// using the formula: `worker threads = number of CPUs * n` where `n` is the value that changes here. /// When multiplier value is 0 or 1 then one thread per core is used. /// Number of worker threads result should be a number between 1 and 32,768 though it is advised to keep this value on the smaller side. pub threads_multiplier: usize, + #[cfg_attr( + not(wasm), + structopt( + long, + short = "b", + default_value = "512", + env = "SERVER_MAX_BLOCKING_THREADS" + ) + )] + #[cfg_attr( + wasm, + structopt( + long, + short = "b", + default_value = "20", + env = "SERVER_MAX_BLOCKING_THREADS" + ) + )] // We use 20 in Wasm, 512 in Native (default for tokio) + /// Maximum number of blocking threads + pub max_blocking_threads: usize, + #[structopt(long, short = "d", default_value = "./public", env = "SERVER_ROOT")] /// Root directory path of static files. pub root: PathBuf, diff --git a/src/settings/file.rs b/src/settings/file.rs index bf103bc..6b8c4cc 100644 --- a/src/settings/file.rs +++ b/src/settings/file.rs @@ -131,6 +131,8 @@ pub struct General { // Worker threads pub threads_multiplier: Option, + pub max_blocking_threads: Option, + pub grace_period: Option, pub page_fallback: Option, diff --git a/src/settings/mod.rs b/src/settings/mod.rs index 9506f19..8bd577f 100644 --- a/src/settings/mod.rs +++ b/src/settings/mod.rs @@ -86,6 +86,7 @@ impl Settings { let mut basic_auth = opts.basic_auth; let mut fd = opts.fd; let mut threads_multiplier = opts.threads_multiplier; + let mut max_blocking_threads = opts.max_blocking_threads; let mut grace_period = opts.grace_period; let mut page_fallback = opts.page_fallback; let mut log_remote_address = opts.log_remote_address; @@ -185,6 +186,9 @@ impl Settings { if let Some(v) = general.threads_multiplier { threads_multiplier = v } + if let Some(v) = general.max_blocking_threads { + max_blocking_threads = v + } if let Some(v) = general.grace_period { grace_period = v } @@ -329,6 +333,7 @@ impl Settings { basic_auth, fd, threads_multiplier, + max_blocking_threads, grace_period, page_fallback, log_remote_address, -- libgit2 1.7.2