Replies: 2 comments 2 replies
-
Sounds like you would be interested in arc-swap as an alternative to a shared mutex! |
Beta Was this translation helpful? Give feedback.
2 replies
-
Something like having the a handler-creator function that takes an pseudo code: function main() {
let user_store = Arc::new(RwLock::new(Hashmap::new()));
let app = App::new();
app.post("/users", users(user_store.clone()));
}
function users(store) {
return function(payload) {
store.add(foo,bar)
return (Ok, json)
}
} Here's my (failing) attempt at applying this to Rust w axum: type UsersStore = Arc<RwLock<HashMap<usize, User>>>;
#[tokio::main]
async fn main() {
let users = UsersStore::default();
let app = Router::new().route("/users", post(create_user(users.clone();)));
let listener = tokio::net::TcpListener::bind("0.0.0.0:8080").await.unwrap();
axum::serve(listener, app).await.unwrap();
}
fn create_user(users: UsersStore) -> impl Fn(Json<CreateUser>) -> Box<dyn Future<Output = (StatusCode, Json<User>)>> {
move |payload| {
async move {
let user = User {
id: 1337,
username: payload.username,
};
users.write().await.insert(user.id, user.clone());
(StatusCode::CREATED, Json(user))
}
}
} |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Summary
I created my first web app using axum and it initially had immutable
AppState
shared between various handlers. TheAppState
holds an active connection to a backend RPC server.Several of the route handlers make use of the RPC connection.
There was a problem that if the backend RPC server was restarted my axum app would continue displaying error pages because it had lost the connection, and it never gets restored.
I fixed this by introducing a watchdog task that periodically checks the RPC connection and creates a new connection if necessary. In order to update the shared state, I introduced mutable shared state via an Arc<RwLock>.
In reality, this solution is fine as only the watchdog mutates the state, and very infrequently, so there is almost no lock contention.
Even still, I am curious how this could be solved without introducing mutable shared state. Especially as it seems a common problem for any webapp that holds an external connection, eg to a DB.
I have one idea, here's a sketch:
AppState
with RPC connection.I believe this would work and should achieve the functionality I have now with mutable shared state. However, its a lot more complex and I think not worth the effort for my low-traffic web app.
So in the end I'm just wondering how others deal with this issue and if there is any recommended pattern?
I think it would be helpful if axum offered some way to replace the shared state. Perhaps something like axum::Serve::set_service(), which would allow replacing the router, which holds the shared state.
If there is an immutable-shared-state example somewhere please point me towards it. Else, I think it would be very helpful to add one.
edit: why do I even care? well because for performance it is nice to have a "shared-nothing" architecture so that none of the requests handlers ever need wait on another one. And the instant we introduce something like an RwLock we lose that compiler guarantee, plus introduce at least a tiny overhead each time we acquire the read lock.
axum version
v0.7.5
Beta Was this translation helpful? Give feedback.
All reactions