Skip to content

Commit

Permalink
Incorporated changes from with_state.md with Vagelis's changes.
Browse files Browse the repository at this point in the history
Vagelis had a similar pull request. Changes were merged.
Added a note about deadlocks. A detailed discussion may not be appropriate.
However, a note that makes people aware of the potential consequences could help reduce pitfalls of share mutable state.
  • Loading branch information
ThanePatrol committed Feb 22, 2023
1 parent 48a0e72 commit e95ba1b
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 8 deletions.
8 changes: 0 additions & 8 deletions axum/src/docs/routing/with_state.md
Expand Up @@ -105,14 +105,6 @@ receives. That means it is not suitable for holding state derived from a
request, such as authorization data extracted in a middleware. Use [`Extension`]
instead for such data.

# Mutable state

As state is used across routes it is not mutable by default. To mutate a state
you will need to use an `Arc<Mutex>` or similar. Accessing mutable IO such as
a database connection requires an async mutex or similar. See the
[tokio discussion on sync vs async mutex](https://docs.rs/tokio/1.25.0/tokio/sync/struct.Mutex.html#which-kind-of-mutex-should-you-use).


# What `S` in `Router<S>` means

`Router<S>` means a router that is _missing_ a state of type `S` to be able to
Expand Down
37 changes: 37 additions & 0 deletions axum/src/extract/state.rs
Expand Up @@ -295,6 +295,43 @@ use std::{
///
/// In general however we recommend you implement `Clone` for all your state types to avoid
/// potential type errors.
///
/// # When mutable shared state is needed
/// As state is used across routes it is not mutable by default. To mutate a state
/// you will need to use an `Arc<Mutex>` or similar.
/// You may have to use `tokio::sync::Mutex` instead of `std::sync::Mutex`,
/// since `std::sync::Mutex` is not safe for use across threads but this comes
/// with performance cost, See the
// [tokio discussion on sync vs async mutex](https://docs.rs/tokio/1.25.0/tokio/sync/struct.Mutex.html#which-kind-of-mutex-should-you-use).
/// for a detailed comparison.
///
/// Be aware that many tasks that require an asynchronous mutex can lead to deadlocks
/// if steps are not taken to prevent a situation where
/// multiple tasks waiting for each other to release the resource.
///
/// ```
/// use axum::extract::{State};
/// use axum::{Router, routing::get};
/// use std::ops::DerefMut;
///
/// struct AppState { data: String }
/// let state = AppState { data: "foo".to_string() };
/// let state = std::sync::Arc::new(tokio::sync::Mutex::new(state));
///
/// let app = Router::new()
/// .route("/", get(handler))
/// .with_state(state);
///
/// async fn handler(State(state): State<std::sync::Arc<tokio::sync::Mutex<AppState>>>) {
/// let mut guard = state.lock().await;
/// let data = guard.deref_mut();
/// // ...
/// }
///
/// # let _: axum::Router = app;
/// ```


#[derive(Debug, Default, Clone, Copy)]
pub struct State<S>(pub S);

Expand Down

0 comments on commit e95ba1b

Please sign in to comment.