darkwing/server/dtos/request/health_dto.rs
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 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
//! Data transfer objects for health check functionality.
//!
//! This module contains the structures and implementations needed to represent
//! the health status of various system components, including databases and
//! services. It supports both detailed and minimal health check responses.
use serde::{Deserialize, Serialize};
/// Key used for S3 health check operations.
/// This key is used to verify S3 bucket accessibility and operations.
pub const HEALTHCHECK_S3_KEY: &str = "darkwing-healthcheck-DONOTDELETE";
/// Response structure for health check endpoints.
///
/// This structure can represent both detailed and minimal health check
/// responses. In minimal mode, only the status and build timestamp are
/// included. In detailed mode, additional information about databases,
/// services, and git metadata is included.
#[derive(Serialize, Deserialize, Default, Debug)]
pub struct HealthResponse {
/// Overall health status of the system.
/// `true` indicates all checked components are healthy.
pub status: bool,
/// Status of database connections.
/// Omitted in the serialized response if None.
#[serde(skip_serializing_if = "Option::is_none")]
pub databases: Option<DatabaseStatus>,
/// Status of external services.
/// Omitted in the serialized response if None.
#[serde(skip_serializing_if = "Option::is_none")]
pub services: Option<ServiceStatuses>,
/// Timestamp when the application was built.
pub build_timestamp: String,
/// Git commit SHA of the deployed version.
/// Omitted in the serialized response if None.
#[serde(skip_serializing_if = "Option::is_none")]
pub git_sha: Option<String>,
/// Timestamp of the git commit.
/// Omitted in the serialized response if None.
#[serde(skip_serializing_if = "Option::is_none")]
pub git_commit_timestamp: Option<String>,
/// Git branch name of the deployed version.
/// Omitted in the serialized response if None.
#[serde(skip_serializing_if = "Option::is_none")]
pub git_branch: Option<String>,
}
impl HealthResponse {
/// Creates a new HealthResponse instance.
///
/// # Arguments
///
/// * `databases` - Optional status of database connections
/// * `services` - Optional status of external services
///
/// # Returns
///
/// Returns a HealthResponse with computed status and appropriate metadata
/// based on whether this is a detailed or minimal health check.
pub fn new(
databases: Option<DatabaseStatus>,
services: Option<ServiceStatuses>,
) -> Self {
let build_timestamp = env!("VERGEN_BUILD_TIMESTAMP").to_string();
let small_response = databases.is_none() && services.is_none();
let (git_sha, git_commit_timestamp, git_branch) = match small_response {
true => (None, None, None),
false => (
Some(env!("VERGEN_GIT_SHA").to_string()),
Some(env!("VERGEN_GIT_COMMIT_TIMESTAMP").to_string()),
Some(env!("VERGEN_GIT_BRANCH").to_string()),
),
};
let status = match (&databases, &services) {
// Both present - check both are ok
(Some(db), Some(svc)) => db.is_ok() && svc.is_ok(),
// Both not present - "small" health request, return true by default
(None, None) => true,
// One present, one not - unhealthy state
_ => false,
};
Self {
status,
databases,
services,
build_timestamp,
git_sha,
git_commit_timestamp,
git_branch,
}
}
}
/// Status information for database connections.
#[derive(Serialize, Deserialize, Default, Debug)]
pub struct DatabaseStatus {
/// Status of the main MySQL database connection.
pub main_mysql: bool,
/// Status of the Redis cache connection.
pub redis_cache: bool,
}
impl DatabaseStatus {
/// Checks if all database connections are healthy.
///
/// # Returns
///
/// Returns `true` if both MySQL and Redis connections are healthy.
pub fn is_ok(&self) -> bool {
self.main_mysql && self.redis_cache
}
}
/// Status information for an individual service.
#[derive(Serialize, Deserialize, Default, Debug)]
pub struct ServiceStatus {
/// Indicates if the service is healthy.
pub status: bool,
/// Optional message providing additional status details.
pub message: Option<String>,
}
/// Collection of service status information.
#[derive(Serialize, Deserialize, Default, Debug)]
pub struct ServiceStatuses {
/// Status of the primary S3 storage service.
pub primary_s3: ServiceStatus,
/// Status of the backup S3 storage service.
pub backup_s3: ServiceStatus,
}
impl ServiceStatuses {
/// Checks if critical services are healthy.
///
/// Currently only checks primary S3 status as backup S3 is not
/// critical for application functionality.
///
/// # Returns
///
/// Returns `true` if critical services are healthy.
pub fn is_ok(&self) -> bool {
self.primary_s3.status
// && self.backup_s3.status // This is not checked as of now, because backup
// S3 is not necessary for the app to function
}
}