index : static-web-server.git

ascending towards madness

author Syrus Akbary <me@syrusakbary.com> 2023-03-07 8:40:56.0 +00:00:00
committer GitHub <noreply@github.com> 2023-03-07 8:40:56.0 +00:00:00
commit
b9fa2bf3fbb26bb98d6b4e671a9233a3ae71aecd [patch]
tree
3a53dcc5ebc526f8ad3da5ff02158309e7763a28
parent
06cba46c5545ce2b5271570320e0e22702bc66b1
download
b9fa2bf3fbb26bb98d6b4e671a9233a3ae71aecd.tar.gz

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(-)

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 <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<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"
        )
    )] // 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<usize>,

    pub max_blocking_threads: Option<usize>,

    pub grace_period: Option<u8>,

    pub page_fallback: Option<PathBuf>,
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,