use displaydoc::Display;
use rand::distributions::Standard;
use rand::prelude::Distribution;
use rand::Rng;
use redis::AsyncCommands as _;
use redis::Client;
use redis::RedisError;
use redis_lock::MultiResourceLock;
use std::error::Error;
use std::time::Duration;
use thiserror::Error;
#[derive(Debug, Display, Error)]
enum CheckError {
Connection(RedisError),
Get(RedisError),
}
async fn check(client: Client, from: &str) -> Result<i64, CheckError> {
let mut conn = client
.get_multiplexed_async_connection()
.await
.map_err(CheckError::Connection)?;
let from_balance: i64 = conn.get(from).await.map_err(CheckError::Get)?;
Ok(from_balance)
}
enum TransferType {
Account1ToAccount2,
Account2ToAccount3,
Account1ToAccount3,
}
#[expect(clippy::unreachable, reason = "It's unreachable and it's a test")]
impl Distribution<TransferType> for Standard {
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> TransferType {
match rng.gen_range(0..3) {
0 => TransferType::Account1ToAccount2,
1 => TransferType::Account2ToAccount3,
2 => TransferType::Account1ToAccount3,
_ => unreachable!(),
}
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let redis_url = "redis://127.0.0.1/";
let client = Client::open(redis_url)?;
let mut lock = MultiResourceLock::new(client.clone())?;
for _ in 0..10usize {
let cloned_client = client.clone();
let _x = lock
.map(
&[String::from("account1")],
Duration::from_secs(60),
Duration::from_secs(2),
Duration::from_millis(100),
async move { check(cloned_client, "account1").await },
)
.await??;
}
Ok(())
}