Skip to main content

max / makenotwork

2.4 KB · 72 lines History Blame Raw
1 //! Scan-pipeline health-check storage.
2 //!
3 //! Unlike the other checks, the scan pipeline was originally only alerted on and
4 //! never persisted, so `/status.json` had nothing to read. This stores the
5 //! latest result per target the same way `backup_checks` does, so the release
6 //! viewer can render it from the ledger rather than re-running a live probe on
7 //! every poll.
8
9 use super::{Result, ScanPipelineCheckResult, SqlitePool};
10 use tracing::instrument;
11
12 #[instrument(skip_all)]
13 pub async fn insert_scan_pipeline_check(
14 pool: &SqlitePool,
15 result: &ScanPipelineCheckResult,
16 ) -> Result<i64> {
17 let issues = serde_json::to_string(&result.issues).unwrap_or_default();
18 let row = sqlx::query(
19 "INSERT INTO scan_pipeline_checks (target, status, issues, queue_pending, queue_running, queue_stuck, held_total, checked_at, error)
20 VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
21 )
22 .bind(&result.target)
23 .bind(&result.status)
24 .bind(&issues)
25 .bind(result.queue_pending)
26 .bind(result.queue_running)
27 .bind(result.queue_stuck)
28 .bind(result.held_total)
29 .bind(&result.checked_at)
30 .bind(&result.error)
31 .execute(pool)
32 .await?;
33 Ok(row.last_insert_rowid())
34 }
35
36 /// The latest scan-pipeline check for a target, if one has been recorded.
37 #[instrument(skip_all)]
38 pub async fn get_latest_scan_pipeline_check(
39 pool: &SqlitePool,
40 target: &str,
41 ) -> Result<Option<ScanPipelineCheckRow>> {
42 Ok(sqlx::query_as::<_, ScanPipelineCheckRow>(
43 "SELECT id, target, status, issues, queue_pending, queue_running, queue_stuck, held_total, checked_at, error
44 FROM scan_pipeline_checks WHERE target = ? ORDER BY id DESC LIMIT 1",
45 )
46 .bind(target)
47 .fetch_optional(pool)
48 .await?)
49 }
50
51 #[derive(Debug, Clone, sqlx::FromRow, serde::Serialize)]
52 pub struct ScanPipelineCheckRow {
53 pub id: i64,
54 pub target: String,
55 pub status: String,
56 /// JSON array of the fired-threshold issue lines. Use [`Self::issue_list`].
57 pub issues: String,
58 pub queue_pending: i64,
59 pub queue_running: i64,
60 pub queue_stuck: i64,
61 pub held_total: i64,
62 pub checked_at: String,
63 pub error: Option<String>,
64 }
65
66 impl ScanPipelineCheckRow {
67 /// Decode the stored issue lines, tolerating a malformed blob as empty.
68 pub fn issue_list(&self) -> Vec<String> {
69 serde_json::from_str(&self.issues).unwrap_or_default()
70 }
71 }
72