-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathquarantine.rs
More file actions
103 lines (88 loc) · 3.34 KB
/
quarantine.rs
File metadata and controls
103 lines (88 loc) · 3.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
//! Quarantine background tasks.
//!
//! Provides scheduled jobs for managing gem version quarantine:
//! - Automatic promotion of versions when quarantine expires
//! - Database migration for quarantine tables
use std::sync::Arc;
use anyhow::{Context, Result};
use chrono::Utc;
use rama::telemetry::tracing;
use tokio_cron_scheduler::{Job, JobScheduler};
use vein_adapter::{CacheBackend, CacheBackendTrait};
use crate::config::DelayPolicyConfig;
/// Default cron schedule for quarantine promotion (every hour at minute 5)
pub const DEFAULT_PROMOTION_SCHEDULE: &str = "0 5 * * * *";
/// Spawns the quarantine promotion scheduler.
///
/// This job runs periodically to promote versions whose quarantine period has expired.
pub fn spawn_promotion_scheduler(
config: &DelayPolicyConfig,
index: Arc<CacheBackend>,
schedule: Option<&str>,
) {
if !config.enabled {
tracing::info!("Quarantine not enabled, skipping promotion scheduler");
return;
}
let schedule = schedule.unwrap_or(DEFAULT_PROMOTION_SCHEDULE).to_string();
std::thread::spawn(move || {
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("Failed to create quarantine scheduler runtime");
rt.block_on(async {
let sched = JobScheduler::new()
.await
.expect("Failed to create quarantine scheduler");
let job = Job::new_async(schedule.as_str(), move |_uuid, _l| {
let index = index.clone();
Box::pin(async move {
let now = Utc::now();
tracing::debug!("Running quarantine promotion check");
match index.promote_expired_quarantines(now).await {
Ok(count) if count > 0 => {
tracing::info!(
promoted = count,
"Promoted quarantined versions to available"
);
}
Ok(_) => {
tracing::debug!("No quarantined versions ready for promotion");
}
Err(err) => {
tracing::error!(error = %err, "Failed to promote quarantined versions");
}
}
})
})
.expect("Failed to create promotion job");
sched
.add(job)
.await
.expect("Failed to add promotion job to scheduler");
sched
.start()
.await
.expect("Failed to start quarantine scheduler");
tracing::info!(
schedule = %schedule,
"Quarantine promotion scheduler started"
);
// Keep the scheduler runtime alive forever
loop {
tokio::time::sleep(tokio::time::Duration::from_secs(3600)).await;
}
});
});
}
/// Manually triggers promotion of expired quarantines.
///
/// Useful for CLI commands.
pub async fn promote_now(index: &CacheBackend) -> Result<u64> {
let now = Utc::now();
let count = index
.promote_expired_quarantines(now)
.await
.context("promoting expired quarantines")?;
Ok(count)
}