add ping endpoint and healthcheck command

This commit is contained in:
Lennart
2025-10-27 21:12:43 +01:00
parent 5d142289b3
commit 77d8f5dacc
5 changed files with 43 additions and 1 deletions

View File

@@ -47,3 +47,5 @@ ENV RUSTICAL_DATA_STORE__SQLITE__DB_URL=/var/lib/rustical/db.sqlite3
LABEL org.opencontainers.image.authors="Lennart K github.com/lennart-k"
LABEL org.opencontainers.image.licenses="AGPL-3.0-or-later"
EXPOSE 4000
HEALTHCHECK --interval=30s --timeout=30s --start-period=3s --retries=3 CMD ["/usr/local/bin/rustical", "health"]

View File

@@ -50,6 +50,8 @@ pub fn make_app<AS: AddressbookStore, CS: CalendarStore, S: SubscriptionStore>(
Arc::new(CombinedCalendarStore::new(cal_store).with_store(birthday_store));
let mut router = Router::new()
// endpoint to be used by healthcheck to see if rustical is online
.route("/ping", axum::routing::get(async || "Pong!"))
.merge(caldav_router(
"/caldav",
auth_provider.clone(),

25
src/commands/health.rs Normal file
View File

@@ -0,0 +1,25 @@
use crate::config::HttpConfig;
use clap::Parser;
use http::Method;
#[derive(Parser, Debug)]
pub struct HealthArgs {}
/// Healthcheck for running rustical instance
/// Currently just pings to see if it's reachable via HTTP
pub async fn cmd_health(http_config: HttpConfig, _health_args: HealthArgs) -> anyhow::Result<()> {
let client = reqwest::ClientBuilder::new().build().unwrap();
let endpoint = format!(
"http://{host}:{port}/ping",
host = http_config.host,
port = http_config.port
)
.parse()
.unwrap();
let request = reqwest::Request::new(Method::GET, endpoint);
assert!(client.execute(request).await.unwrap().status().is_success());
Ok(())
}

View File

@@ -5,7 +5,8 @@ use crate::config::{
use clap::Parser;
use rustical_frontend::FrontendConfig;
mod membership;
pub mod health;
pub mod membership;
pub mod principals;
#[derive(Debug, Parser)]

View File

@@ -1,4 +1,5 @@
#![warn(clippy::all, clippy::pedantic, clippy::nursery)]
use crate::commands::health::{HealthArgs, cmd_health};
use crate::config::Config;
use anyhow::Result;
use app::make_app;
@@ -45,6 +46,10 @@ struct Args {
enum Command {
GenConfig(commands::GenConfigArgs),
Principals(PrincipalsArgs),
#[command(
about = "Healthcheck for running instance (Used for HEALTHCHECK in Docker container)"
)]
Health(HealthArgs),
}
async fn get_data_stores(
@@ -85,6 +90,13 @@ async fn main() -> Result<()> {
match args.command {
Some(Command::GenConfig(gen_config_args)) => cmd_gen_config(gen_config_args)?,
Some(Command::Principals(principals_args)) => cmd_principals(principals_args).await?,
Some(Command::Health(health_args)) => {
let config: Config = Figment::new()
.merge(Toml::file(&args.config_file))
.merge(Env::prefixed("RUSTICAL_").split("__"))
.extract()?;
cmd_health(config.http, health_args).await?;
}
None => {
let config: Config = Figment::new()
.merge(Toml::file(&args.config_file))