use crate::Client;
use std::sync::Arc;
use tokio::sync::{Mutex, OwnedMutexGuard};
use uuid::Uuid;
#[derive(Debug)]
pub struct Lease {
client: Client,
key_lease_v: Arc<(String, Mutex<Uuid>)>,
local_guard: Option<OwnedMutexGuard<()>>,
release_on_drop: bool,
}
impl Lease {
pub(crate) fn new(client: Client, key: String, lease_v: Uuid) -> Self {
let lease = Self {
client,
key_lease_v: Arc::new((key, Mutex::new(lease_v))),
local_guard: None,
release_on_drop: true,
};
start_periodically_extending(&lease);
lease
}
pub(crate) fn with_local_guard(mut self, guard: OwnedMutexGuard<()>) -> Self {
self.local_guard = Some(guard);
self
}
pub async fn release(mut self) -> anyhow::Result<()> {
self.release_on_drop = false;
let (key, lease_v) = &*self.key_lease_v;
drop(self.local_guard.take());
self.client.try_clean_local_lock(key.clone());
let lease_v = lease_v.lock().await;
self.client.delete_lease(key.clone(), *lease_v).await?;
drop(lease_v); Ok(())
}
pub fn is_healthy(&self) -> bool {
Arc::weak_count(&self.key_lease_v) != 0
}
}
fn start_periodically_extending(lease: &Lease) {
let key_lease_v = Arc::downgrade(&lease.key_lease_v);
let client = lease.client.clone();
tokio::spawn(async move {
let mut extend_interval = tokio::time::interval(client.extend_period);
extend_interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
extend_interval.reset();
loop {
extend_interval.tick().await;
match key_lease_v.upgrade() {
Some(key_lease_v) => {
let mut lease_v = key_lease_v.1.lock().await;
let key = key_lease_v.0.clone();
match client.extend_lease(key, *lease_v).await {
Ok(new_lease_v) => {
*lease_v = new_lease_v;
}
Err(_) => break,
}
}
None => break,
}
}
});
}
impl Drop for Lease {
fn drop(&mut self) {
if self.release_on_drop {
let lease = Lease {
client: self.client.clone(),
key_lease_v: Arc::clone(&self.key_lease_v),
local_guard: self.local_guard.take(), release_on_drop: false,
};
tokio::spawn(async move {
_ = lease.release().await;
});
}
}
}