I have a gRPC server method for which I want to simulate some work for this I have this
async fn write(&self, request: Request<WriteRequest>)
-> Result<Response<WriteResponse>, Status> {
let mut rng = rand::thread_rng();
let random = rng.gen_range(1000..5000);
// Sleep for the random duration
sleep(Duration::from_millis(random)).await;
return Ok(Response::new(WriteResponse { ... }));
}
but the code is not happy about the random value, I get the error
future cannot be sent between threads safely future created by async block is not `Send`
I know I can add + Send in the function but in this case, I cannot modify the signature of the method because it is an interface generated by the gRPC compiler
When I used hardcoded value within the Duration in works.
How can I call the random number generation? or how can I sleep for a random value using sleep? is there another way?
This happens because rng
is held past an await point. You can get around this by enclosing it in a block, which ensures it is not stored in the async function's state machine.
let random_secs = {
let mut rng = rand::thread_rng();
rng.gen_range(1000..5000)
};
If you do need to store an RNG, you can store a normal PRNG (such as StdRng
) that is seeded from thread_rng
.
use rand::{Rng, SeedableRng, rngs::StdRng};
let mut rng = {
let rng = rand::thread_rng();
StdRng::from_rng(rng).unwrap()
};
loop {
let millis = rng.gen_range(1..10);
tokio::time::sleep(std::time::Duration::from_millis(millis)).await;
println!("{millis}");
}