Skip to main content

alopex_server/ops/
status.rs

1use std::sync::Arc;
2
3use serde::{Deserialize, Serialize};
4
5use crate::metrics::Metrics;
6use crate::ops::recovery::RecoveryInfo;
7use crate::ops::state::{LifecycleStateManager, Mode, OperationState, RestoreMetadata};
8
9#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
10#[serde(rename_all = "snake_case")]
11pub enum OverallStatus {
12    Ok,
13    Degraded,
14}
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct StatusView {
18    pub overall_status: OverallStatus,
19    pub read_only: bool,
20    pub maintenance: bool,
21    pub recovery_state: RecoveryInfo,
22    pub backup_state: OperationState,
23    pub restore_state: OperationState,
24    pub restore_metadata: Option<RestoreMetadata>,
25    pub last_recovery_at_ms: Option<u64>,
26    pub last_backup_at_ms: Option<u64>,
27    pub last_restore_at_ms: Option<u64>,
28}
29
30#[derive(Debug, Clone)]
31pub struct StatusReporter {
32    lifecycle_state: Arc<LifecycleStateManager>,
33    recovery_info: RecoveryInfo,
34}
35
36impl StatusReporter {
37    pub fn new(lifecycle_state: Arc<LifecycleStateManager>, recovery_info: RecoveryInfo) -> Self {
38        Self {
39            lifecycle_state,
40            recovery_info,
41        }
42    }
43
44    pub fn status_view(&self) -> StatusView {
45        let mode = self.lifecycle_state.current_mode();
46        let read_only = mode == Mode::ReadOnly;
47        let maintenance = mode == Mode::Maintenance;
48        let overall_status = if read_only || maintenance {
49            OverallStatus::Degraded
50        } else {
51            OverallStatus::Ok
52        };
53
54        let backup_state = self.lifecycle_state.backup_state();
55        let restore_state = self.lifecycle_state.restore_state();
56        let restore_metadata = self.lifecycle_state.restore_metadata();
57        let last_recovery_at_ms = Some(self.recovery_info.finished_at_ms);
58        let last_backup_at_ms = backup_state.finished_at_ms;
59        let last_restore_at_ms = restore_metadata
60            .as_ref()
61            .map(|meta| meta.restored_at_ms)
62            .or(restore_state.finished_at_ms);
63
64        StatusView {
65            overall_status,
66            read_only,
67            maintenance,
68            recovery_state: self.recovery_info.clone(),
69            backup_state,
70            restore_state,
71            restore_metadata,
72            last_recovery_at_ms,
73            last_backup_at_ms,
74            last_restore_at_ms,
75        }
76    }
77
78    pub fn refresh_metrics(&self, metrics: &Metrics) {
79        let view = self.status_view();
80        metrics.record_operational_state(
81            &view.recovery_state,
82            &view.backup_state,
83            &view.restore_state,
84        );
85    }
86}