mirror of
https://github.com/tokio-rs/axum.git
synced 2026-08-17 00:00:16 +02:00
axum: add docs describing how, why and when to use &'static state (#3838)
This commit is contained in:
+70
-1
@@ -186,7 +186,76 @@
|
||||
//! State is cloned for every request. Wrapping your state in `Arc` makes those
|
||||
//! clones cheap. If all fields are already cheap to clone (for example, each field
|
||||
//! is itself an `Arc` or a copy type), you can `#[derive(Clone)]` directly on the
|
||||
//! struct instead.
|
||||
//! struct instead. Many client types, such as [`reqwest::Client`], AWS SDK service
|
||||
//! clients, and [`mongodb::Client`], already use shared ownership internally and
|
||||
//! are cheap to clone. Such clients generally do not need another `Arc` solely to
|
||||
//! make cloning cheap; doing so adds another level of indirection.
|
||||
//!
|
||||
//! [`reqwest::Client`]: https://docs.rs/reqwest/latest/reqwest/struct.Client.html
|
||||
//! [`mongodb::Client`]: https://docs.rs/mongodb/latest/mongodb/struct.Client.html
|
||||
//!
|
||||
//! ### Using `&'static` state
|
||||
//!
|
||||
//! For state built once and intended to live until the process exits, [`Box::leak`]
|
||||
//! or a static [`LazyLock`] can provide a `&'static AppState` to the router. Use
|
||||
//! `Box::leak` for state initialized in `main`, including when state initialization
|
||||
//! requires asynchronous work; use a static `LazyLock` for global state with a
|
||||
//! synchronous lazy initializer. This is useful for state built from runtime
|
||||
//! configuration, database pools, or service clients:
|
||||
//!
|
||||
//! ```rust
|
||||
//! use axum::{
|
||||
//! extract::State,
|
||||
//! routing::get,
|
||||
//! Router,
|
||||
//! };
|
||||
//!
|
||||
//! struct AppState {
|
||||
//! // A database pool, service clients, configuration, etc.
|
||||
//! }
|
||||
//!
|
||||
//! impl AppState {
|
||||
//! async fn work(&self) {}
|
||||
//! }
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let app_state = AppState {
|
||||
//! // Initialize fields at startup.
|
||||
//! };
|
||||
//! let app_state: &'static AppState = Box::leak(Box::new(app_state));
|
||||
//!
|
||||
//! let app = Router::new()
|
||||
//! .route("/", get(handler))
|
||||
//! .with_state(app_state);
|
||||
//! # let _: Router = app;
|
||||
//! }
|
||||
//!
|
||||
//! async fn handler(State(state): State<&'static AppState>) {
|
||||
//! let _task = tokio::spawn(async move {
|
||||
//! state.work().await;
|
||||
//! });
|
||||
//!
|
||||
//! // `state` is still available in the handler because it was copied.
|
||||
//! state.work().await;
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Like every shared reference, a `&'static T` is `Copy`, so axum can clone it for
|
||||
//! each request without an atomic reference-count operation. This can be cheaper than
|
||||
//! cloning an `Arc`, but it is rarely a reason on its own to choose process-lifetime
|
||||
//! state since the request's actual work normally matters more. The more practical
|
||||
//! advantage of combining `Copy` with the `'static` lifetime is shown above: an
|
||||
//! `async move` block copies the reference into the spawned Tokio task while leaving
|
||||
//! the handler's copy available. With `Arc`, call [`Arc::clone`] before spawning when
|
||||
//! the handler also needs the state.
|
||||
//!
|
||||
//! `Box::leak` deliberately leaks its allocation, and state held by a static
|
||||
//! `LazyLock` is likewise never dropped. Use either only for process-lifetime state.
|
||||
//! Use `Arc` when the state needs a managed lifetime.
|
||||
//!
|
||||
//! [`Arc::clone`]: https://doc.rust-lang.org/std/sync/struct.Arc.html#method.clone
|
||||
//! [`Box::leak`]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.leak
|
||||
//! [`LazyLock`]: https://doc.rust-lang.org/std/sync/struct.LazyLock.html
|
||||
//!
|
||||
//! ### Substates with `FromRef`
|
||||
//!
|
||||
|
||||
Reference in New Issue
Block a user