alopex-server 0.5.0

Server component for Alopex DB
Documentation
use std::sync::Arc;

use serde::{Deserialize, Serialize};

use crate::metrics::Metrics;
use crate::ops::recovery::RecoveryInfo;
use crate::ops::state::{LifecycleStateManager, Mode, OperationState, RestoreMetadata};

#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum OverallStatus {
    Ok,
    Degraded,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StatusView {
    pub overall_status: OverallStatus,
    pub read_only: bool,
    pub maintenance: bool,
    pub recovery_state: RecoveryInfo,
    pub backup_state: OperationState,
    pub restore_state: OperationState,
    pub restore_metadata: Option<RestoreMetadata>,
    pub last_recovery_at_ms: Option<u64>,
    pub last_backup_at_ms: Option<u64>,
    pub last_restore_at_ms: Option<u64>,
}

#[derive(Debug, Clone)]
pub struct StatusReporter {
    lifecycle_state: Arc<LifecycleStateManager>,
    recovery_info: RecoveryInfo,
}

impl StatusReporter {
    pub fn new(lifecycle_state: Arc<LifecycleStateManager>, recovery_info: RecoveryInfo) -> Self {
        Self {
            lifecycle_state,
            recovery_info,
        }
    }

    pub fn status_view(&self) -> StatusView {
        let mode = self.lifecycle_state.current_mode();
        let read_only = mode == Mode::ReadOnly;
        let maintenance = mode == Mode::Maintenance;
        let overall_status = if read_only || maintenance {
            OverallStatus::Degraded
        } else {
            OverallStatus::Ok
        };

        let backup_state = self.lifecycle_state.backup_state();
        let restore_state = self.lifecycle_state.restore_state();
        let restore_metadata = self.lifecycle_state.restore_metadata();
        let last_recovery_at_ms = Some(self.recovery_info.finished_at_ms);
        let last_backup_at_ms = backup_state.finished_at_ms;
        let last_restore_at_ms = restore_metadata
            .as_ref()
            .map(|meta| meta.restored_at_ms)
            .or(restore_state.finished_at_ms);

        StatusView {
            overall_status,
            read_only,
            maintenance,
            recovery_state: self.recovery_info.clone(),
            backup_state,
            restore_state,
            restore_metadata,
            last_recovery_at_ms,
            last_backup_at_ms,
            last_restore_at_ms,
        }
    }

    pub fn refresh_metrics(&self, metrics: &Metrics) {
        let view = self.status_view();
        metrics.record_operational_state(
            &view.recovery_state,
            &view.backup_state,
            &view.restore_state,
        );
    }
}