#[cfg(feature = "distributed")]
mod redis_impl;
#[cfg(feature = "distributed")]
pub use redis_impl::{CoordinationManager, RedisCoordination};
#[async_trait::async_trait]
pub trait CoordinationBackend: Send + Sync {
async fn try_acquire_lock(&self, key: &str, ttl_secs: u64) -> anyhow::Result<bool>;
async fn release_lock(&self, key: &str) -> anyhow::Result<()>;
async fn is_locked(&self, key: &str) -> anyhow::Result<bool>;
async fn heartbeat(&self, instance_id: &str, ttl_secs: u64) -> anyhow::Result<()>;
async fn is_instance_alive(&self, instance_id: &str) -> anyhow::Result<bool>;
async fn try_become_leader(&self, instance_id: &str, lease_secs: u64) -> anyhow::Result<bool>;
async fn is_leader(&self, instance_id: &str) -> anyhow::Result<bool>;
async fn get_current_leader(&self) -> anyhow::Result<Option<String>>;
}
#[derive(Debug, Clone)]
pub struct CoordinationConfig {
pub instance_id: String,
pub redis_url: String,
pub leader_lease_secs: u64,
pub heartbeat_interval_secs: u64,
pub lock_ttl_secs: u64,
}
impl Default for CoordinationConfig {
fn default() -> Self {
Self {
instance_id: format!("instance-{}", uuid::Uuid::new_v4()),
redis_url: "redis://localhost:6379".to_string(),
leader_lease_secs: 30,
heartbeat_interval_secs: 5,
lock_ttl_secs: 300, }
}
}
impl CoordinationConfig {
pub fn with_instance_id(mut self, id: impl Into<String>) -> Self {
self.instance_id = id.into();
self
}
pub fn with_redis_url(mut self, url: impl Into<String>) -> Self {
self.redis_url = url.into();
self
}
pub fn with_leader_lease(mut self, secs: u64) -> Self {
self.leader_lease_secs = secs;
self
}
pub fn with_heartbeat_interval(mut self, secs: u64) -> Self {
self.heartbeat_interval_secs = secs;
self
}
}