fc-queue-runner: implement persistent notification retry queue with exponential backoff

Adds a `notification_tasks` table and a background worker to (hopefully
reliably) deliver webhooks, git status updates, and e-mail notifications
with automatic retry on transient failures.

This was one of the critical gaps, finally done.

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I794967c66958658c4d8aed40793d67f96a6a6964
This commit is contained in:
raf 2026-02-27 21:19:32 +03:00
commit 21446c6dcb
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF
8 changed files with 849 additions and 8 deletions

View file

@ -134,14 +134,26 @@ impl std::fmt::Debug for GitHubOAuthConfig {
#[serde(default)]
#[derive(Default)]
pub struct NotificationsConfig {
pub webhook_url: Option<String>,
pub github_token: Option<String>,
pub gitea_url: Option<String>,
pub gitea_token: Option<String>,
pub gitlab_url: Option<String>,
pub gitlab_token: Option<String>,
pub email: Option<EmailConfig>,
pub alerts: Option<AlertConfig>,
pub webhook_url: Option<String>,
pub github_token: Option<String>,
pub gitea_url: Option<String>,
pub gitea_token: Option<String>,
pub gitlab_url: Option<String>,
pub gitlab_token: Option<String>,
pub email: Option<EmailConfig>,
pub alerts: Option<AlertConfig>,
/// Enable notification retry queue (persistent, with exponential backoff)
#[serde(default = "default_true")]
pub enable_retry_queue: bool,
/// Maximum retry attempts per notification (default 5)
#[serde(default = "default_notification_max_attempts")]
pub max_retry_attempts: i32,
/// Retention period for old completed/failed tasks in days (default 7)
#[serde(default = "default_notification_retention_days")]
pub retention_days: i64,
/// Polling interval for retry worker in seconds (default 5)
#[serde(default = "default_notification_poll_interval")]
pub retry_poll_interval: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
@ -434,6 +446,18 @@ fn default_role() -> String {
"read-only".to_string()
}
const fn default_notification_max_attempts() -> i32 {
5
}
const fn default_notification_retention_days() -> i64 {
7
}
const fn default_notification_poll_interval() -> u64 {
5
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct TracingConfig {