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 <johnathan.sharratt@gmail.com>
Co-authored-by: Jose Quintana <joseluisquintana20@gmail.com>
Diff
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(-)
@@ -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 <max-blocking-threads>
Maximum number of blocking threads
[default: 512]
```
## Windows
@@ -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).
@@ -18,7 +18,8 @@ use crate::{service::RouterService, Context, Result};
pub struct Server {
opts: Settings,
threads: usize,
worker_threads: usize,
max_blocking_threads: usize,
}
impl Server {
@@ -29,12 +30,17 @@ impl Server {
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,
})
}
@@ -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());
let threads = self.threads;
let threads = self.worker_threads;
tracing::info!("runtime worker threads: {}", threads);
tracing::info!(
"runtime max blocking threads: {}",
general.max_blocking_threads
);
let security_headers = general.security_headers;
tracing::info!("security headers: enabled={}", security_headers);
@@ -32,18 +32,51 @@ pub struct General {
pub fd: Option<usize>,
#[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"
)
)] 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"
)
)] pub max_blocking_threads: usize,
#[structopt(long, short = "d", default_value = "./public", env = "SERVER_ROOT")]
pub root: PathBuf,
@@ -131,6 +131,8 @@ pub struct General {
pub threads_multiplier: Option<usize>,
pub max_blocking_threads: Option<usize>,
pub grace_period: Option<u8>,
pub page_fallback: Option<PathBuf>,
@@ -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,