use std::fmt;
use std::time::Duration;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum DriverKind {
Memory,
Redis,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum BackoffStrategy {
Exponential,
Linear,
Fixed,
}
impl BackoffStrategy {
pub fn delay(&self, base: Duration, attempt: u32) -> Duration {
match self {
Self::Exponential => base.saturating_mul(1u32 << attempt.min(10)),
Self::Linear => base.saturating_mul(attempt + 1),
Self::Fixed => base,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct QueueConfig {
pub name: String,
pub concurrency: usize,
pub max_retries: u32,
#[serde(with = "humantime_serde")]
pub retry_delay: Duration,
pub retry_backoff: BackoffStrategy,
#[serde(with = "humantime_serde")]
pub job_timeout: Duration,
pub dead_letter_queue: Option<String>,
pub priority: u32,
}
impl Default for QueueConfig {
fn default() -> Self {
Self {
name: "default".into(),
concurrency: 4,
max_retries: 3,
retry_delay: Duration::from_secs(1),
retry_backoff: BackoffStrategy::Exponential,
job_timeout: Duration::from_secs(60),
dead_letter_queue: None,
priority: 10,
}
}
}
#[derive(Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct JobsConfig {
pub driver: DriverKind,
pub host: String,
pub port: u16,
pub password: String,
pub db: u32,
pub queues: Vec<QueueConfig>,
}
impl fmt::Debug for JobsConfig {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("JobsConfig")
.field("driver", &self.driver)
.field("host", &self.host)
.field("port", &self.port)
.field("password", &"[REDACTED]")
.field("db", &self.db)
.field("queues", &self.queues)
.finish()
}
}
impl JobsConfig {
pub fn redis_url(&self) -> String {
let auth = if self.password.is_empty() {
String::new()
} else {
format!(":{}@", self.password)
};
format!("redis://{}{}:{}/{}", auth, self.host, self.port, self.db)
}
}
impl Default for JobsConfig {
fn default() -> Self {
Self {
driver: DriverKind::Memory,
host: "127.0.0.1".into(),
port: 6379,
password: String::new(),
db: 0,
queues: vec![QueueConfig::default()],
}
}
}