|
186 | 186 | //! State is cloned for every request. Wrapping your state in `Arc` makes those |
187 | 187 | //! clones cheap. If all fields are already cheap to clone (for example, each field |
188 | 188 | //! is itself an `Arc` or a copy type), you can `#[derive(Clone)]` directly on the |
189 | | -//! struct instead. |
| 189 | +//! struct instead. Many client types, such as [`reqwest::Client`], AWS SDK service |
| 190 | +//! clients, and [`mongodb::Client`], already use shared ownership internally and |
| 191 | +//! are cheap to clone. Such clients generally do not need another `Arc` solely to |
| 192 | +//! make cloning cheap; doing so adds another level of indirection. |
| 193 | +//! |
| 194 | +//! [`reqwest::Client`]: https://docs.rs/reqwest/latest/reqwest/struct.Client.html |
| 195 | +//! [`mongodb::Client`]: https://docs.rs/mongodb/latest/mongodb/struct.Client.html |
| 196 | +//! |
| 197 | +//! ### Using `&'static` state |
| 198 | +//! |
| 199 | +//! For state built once and intended to live until the process exits, [`Box::leak`] |
| 200 | +//! or a static [`LazyLock`] can provide a `&'static AppState` to the router. Use |
| 201 | +//! `Box::leak` for state initialized in `main`, including when state initialization |
| 202 | +//! requires asynchronous work; use a static `LazyLock` for global state with a |
| 203 | +//! synchronous lazy initializer. This is useful for state built from runtime |
| 204 | +//! configuration, database pools, or service clients: |
| 205 | +//! |
| 206 | +//! ```rust |
| 207 | +//! use axum::{ |
| 208 | +//! extract::State, |
| 209 | +//! routing::get, |
| 210 | +//! Router, |
| 211 | +//! }; |
| 212 | +//! |
| 213 | +//! struct AppState { |
| 214 | +//! // A database pool, service clients, configuration, etc. |
| 215 | +//! } |
| 216 | +//! |
| 217 | +//! impl AppState { |
| 218 | +//! async fn work(&self) {} |
| 219 | +//! } |
| 220 | +//! |
| 221 | +//! fn main() { |
| 222 | +//! let app_state = AppState { |
| 223 | +//! // Initialize fields at startup. |
| 224 | +//! }; |
| 225 | +//! let app_state: &'static AppState = Box::leak(Box::new(app_state)); |
| 226 | +//! |
| 227 | +//! let app = Router::new() |
| 228 | +//! .route("/", get(handler)) |
| 229 | +//! .with_state(app_state); |
| 230 | +//! # let _: Router = app; |
| 231 | +//! } |
| 232 | +//! |
| 233 | +//! async fn handler(State(state): State<&'static AppState>) { |
| 234 | +//! let _task = tokio::spawn(async move { |
| 235 | +//! state.work().await; |
| 236 | +//! }); |
| 237 | +//! |
| 238 | +//! // `state` is still available in the handler because it was copied. |
| 239 | +//! state.work().await; |
| 240 | +//! } |
| 241 | +//! ``` |
| 242 | +//! |
| 243 | +//! Like every shared reference, a `&'static T` is `Copy`, so axum can clone it for |
| 244 | +//! each request without an atomic reference-count operation. This can be cheaper than |
| 245 | +//! cloning an `Arc`, but it is rarely a reason on its own to choose process-lifetime |
| 246 | +//! state since the request's actual work normally matters more. The more practical |
| 247 | +//! advantage of combining `Copy` with the `'static` lifetime is shown above: an |
| 248 | +//! `async move` block copies the reference into the spawned Tokio task while leaving |
| 249 | +//! the handler's copy available. With `Arc`, call [`Arc::clone`] before spawning when |
| 250 | +//! the handler also needs the state. |
| 251 | +//! |
| 252 | +//! `Box::leak` deliberately leaks its allocation, and state held by a static |
| 253 | +//! `LazyLock` is likewise never dropped. Use either only for process-lifetime state. |
| 254 | +//! Use `Arc` when the state needs a managed lifetime. |
| 255 | +//! |
| 256 | +//! [`Arc::clone`]: https://doc.rust-lang.org/std/sync/struct.Arc.html#method.clone |
| 257 | +//! [`Box::leak`]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.leak |
| 258 | +//! [`LazyLock`]: https://doc.rust-lang.org/std/sync/struct.LazyLock.html |
190 | 259 | //! |
191 | 260 | //! ### Substates with `FromRef` |
192 | 261 | //! |
|
0 commit comments