I have an ABC struct with work function which modifies a field on the struct, the field is Arc<Mutex<HashSet<u64>>>,.
My goal is to expose the work method at the do_work endpoint via Axum
// I need to create ABC object since the constructor(`new`) have some init functionality
let worker = ABC::new();
// Now, I want to call worker.work() method when the do_work is called.
let app = Router::new()
.route("/do_work", get(worker.work))
This code doesn't work.
How can I solve the issue?
// doesn't work as well
async { worker.work().await }
I need new to be called due to init functionality, I need work to call and it's modifies the shared data
If you want to use the worker with multiple routes, you need some kind of shared ownership like an Arc
use std::{
collections::HashSet,
sync::{Arc, Mutex},
};
use axum::{routing::get, Router};
struct Worker {
hash_set: Mutex<HashSet<u64>>,
}
impl Worker {
async fn health_check(&self) {
self.hash_set.lock().unwrap().insert(12);
}
}
#[tokio::main]
async fn main() {
let worker = Arc::new(Worker {
hash_set: Mutex::new(HashSet::new()),
});
let app = Router::new()
.route(
"/",
get(
// Note this is just a block that returns a closure.
// It groups the clone with the closure nicely
{
// Clone the worker so we can move it into the route closure
let worker = worker.clone();
|| async move {
worker.health_check().await;
}
},
),
)
.route(
"/print",
// Don't need to clone here since nothing else uses the worker afterwards.
// We can just move the original Arc into this closure.
get(|| async move { format!("{:#?}", worker.hash_set.lock().unwrap()) }),
);
axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
.serve(app.into_make_service())
.await
.unwrap();
}