use std::time::Duration;
pub mod db;
pub mod default;
#[cfg(feature = "email")]
pub mod email;
pub mod registry;
#[cfg(feature = "sidekiq")]
pub mod sidekiq_enqueue;
#[cfg(feature = "sidekiq")]
pub mod sidekiq_fetch;
use crate::error::RoadsterResult;
use async_trait::async_trait;
#[cfg(feature = "open-api")]
use schemars::JsonSchema;
use serde_derive::{Deserialize, Serialize};
use serde_json::Value;
use serde_with::{serde_as, skip_serializing_none};
use tracing::error;
use typed_builder::TypedBuilder;
#[serde_as]
#[skip_serializing_none]
#[derive(Debug, Clone, Serialize, Deserialize, TypedBuilder)]
#[cfg_attr(feature = "open-api", derive(JsonSchema))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct CheckResponse {
pub status: Status,
#[builder(setter(transform = |duration: std::time::Duration| duration.as_millis()))]
pub latency: u128,
#[builder(
default,
setter(transform = |custom: impl serde::Serialize| serialize_custom(custom))
)]
pub custom: Option<Value>,
}
fn serialize_custom(custom: impl serde::Serialize) -> Option<Value> {
Some(
serde_json::to_value(custom)
.unwrap_or_else(|err| Value::String(format!("Unable to serialize custom data: {err}"))),
)
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "open-api", derive(JsonSchema))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub enum Status {
Ok,
Err(ErrorData),
}
#[derive(Debug, Clone, Serialize, Deserialize, TypedBuilder)]
#[cfg_attr(feature = "open-api", derive(JsonSchema))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct ErrorData {
#[serde(skip_serializing_if = "Option::is_none")]
#[builder(default, setter(strip_option))]
pub msg: Option<String>,
}
#[cfg_attr(test, mockall::automock)]
#[async_trait]
pub trait HealthCheck: Send + Sync {
fn name(&self) -> String;
fn enabled(&self) -> bool;
async fn check(&self) -> RoadsterResult<CheckResponse>;
}
#[allow(dead_code)]
fn missing_context_response() -> CheckResponse {
let msg = "AppContext missing; is the app shutting down?".to_string();
error!(msg);
CheckResponse::builder()
.status(Status::Err(ErrorData::builder().msg(msg).build()))
.latency(Duration::from_secs(0))
.build()
}
#[cfg(test)]
mod tests {
use insta::assert_json_snapshot;
#[test]
fn missing_context_response() {
assert_json_snapshot!(super::missing_context_response());
}
}