From 517f3779cdfe5132e52b55b7fe3c5174f061d58e Mon Sep 17 00:00:00 2001 From: Charles GTE Date: Fri, 27 Mar 2026 23:07:06 +0100 Subject: [PATCH 1/3] feat: sending database ping result for each databases to portabase server --- src/services/api/endpoints/agent/status.rs | 2 ++ src/services/status.rs | 22 +++++++++++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/services/api/endpoints/agent/status.rs b/src/services/api/endpoints/agent/status.rs index 868a4d4..8c7a5ce 100644 --- a/src/services/api/endpoints/agent/status.rs +++ b/src/services/api/endpoints/agent/status.rs @@ -11,6 +11,8 @@ pub struct DatabasePayload<'a> { pub dbms: &'a str, #[serde(rename = "generatedId")] pub generated_id: &'a str, + #[serde(rename = "pingStatus")] + pub ping_status: bool } #[derive(Serialize)] diff --git a/src/services/status.rs b/src/services/status.rs index 0ddfba1..3bb2bb3 100644 --- a/src/services/status.rs +++ b/src/services/status.rs @@ -8,6 +8,8 @@ use crate::settings::CONFIG; use reqwest::Client; use std::error::Error; use std::sync::Arc; +use futures_util::future::try_join_all; +use crate::domain::factory::DatabaseFactory; pub struct StatusService { ctx: Arc, @@ -25,14 +27,20 @@ impl StatusService { pub async fn ping(&self, databases: &[DatabaseConfig]) -> Result> { let edge_key = &self.ctx.edge_key; - let databases_payload: Vec = databases - .iter() - .map(|db| DatabasePayload { - name: &db.name, - dbms: &db.db_type.as_str(), - generated_id: &db.generated_id, + let databases_payload: Vec = try_join_all( + databases.into_iter().map(|db| async move { + let db_engine = DatabaseFactory::create_for_backup(db.clone()).await; + + let reachable = db_engine.ping().await?; + + Ok::(DatabasePayload { + name: &db.name, + dbms: &db.db_type.as_str(), + generated_id: &db.generated_id, + ping_status: reachable, + }) }) - .collect(); + ).await?; let version_str = CONFIG.app_version.as_str(); let result = self From 3d5a7eededdb8229eb1fe7f2f43affb2d3975b3b Mon Sep 17 00:00:00 2001 From: Charles GTE Date: Sat, 28 Mar 2026 16:07:37 +0100 Subject: [PATCH 2/3] feat: add health check ping for databases --- docker-compose.prod.yml | 7 ++----- docker-compose.yml | 2 +- src/domain/redis/ping.rs | 13 +++++++------ src/domain/valkey/ping.rs | 17 +++++++++-------- src/settings.rs | 10 ++++++++++ 5 files changed, 29 insertions(+), 20 deletions(-) diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index cd4e525..f0cb939 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -5,23 +5,20 @@ services: # dockerfile: docker/Dockerfile # target: prod image: portabase/agent:latest -# platform: linux/arm64 container_name: rust-prod volumes: - ./databases.json:/config/config.json environment: - # APP_ENV: production LOG: info TZ: "Europe/Paris" - # DATABASES_CONFIG_FILE: "config.toml" - EDGE_KEY: "eyJzZXJ2ZXJVcmwiOiJodHRwOi8vbG9jYWxob3N0Ojg4ODciLCJhZ2VudElkIjoiNWU1OGU2MGEtODhiMy00YTBjLWI0NDktNTQ3OWZhOTQzZDBkIiwibWFzdGVyS2V5QjY0IjoiQlhWM1hvbEM2NTZTVjdkTmdjV1BHUWxrKytycExJNmxHRGk3Q1BCNWllbz0ifQ==" + #DATABASES_CONFIG_FILE: "config.toml" + EDGE_KEY: "" extra_hosts: - "localhost:host-gateway" networks: - portabase - db-mongodb-auth: container_name: db-mongodb-auth image: mongo:latest diff --git a/docker-compose.yml b/docker-compose.yml index 7b19a5e..ca3c860 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -21,7 +21,7 @@ services: LOG: debug TZ: "Europe/Paris" EDGE_KEY: "eyJzZXJ2ZXJVcmwiOiJodHRwOi8vbG9jYWxob3N0Ojg4ODciLCJhZ2VudElkIjoiNGI1OTM2MGItNTNkMi00ZTZmLWE1ODctODcyMmQ1NDc1MTNmIiwibWFzdGVyS2V5QjY0IjoiQlhWM1hvbEM2NTZTVjdkTmdjV1BHUWxrKytycExJNmxHRGk3Q1BCNWllbz0ifQ==" - #POOLING: 1 +# POOLING: 900 #DATABASES_CONFIG_FILE: "config.toml" extra_hosts: - "localhost:host-gateway" diff --git a/src/domain/redis/ping.rs b/src/domain/redis/ping.rs index 82b2b9b..c53b822 100644 --- a/src/domain/redis/ping.rs +++ b/src/domain/redis/ping.rs @@ -2,7 +2,7 @@ use crate::services::config::DatabaseConfig; use anyhow::{Context, Result}; use tokio::process::Command; use tokio::time::{Duration, timeout}; -use tracing::{debug, info}; +use tracing::{debug, error, info}; pub async fn run(cfg: DatabaseConfig) -> Result { let mut cmd = Command::new("redis-cli"); @@ -21,7 +21,7 @@ pub async fn run(cfg: DatabaseConfig) -> Result { cmd.arg("PING"); - debug!("Command Ping: {:?}", cmd); + debug!("Command Ping Redis: {:?}", cmd); let result = timeout(Duration::from_secs(10), cmd.output()).await; @@ -31,16 +31,17 @@ pub async fn run(cfg: DatabaseConfig) -> Result { let stdout = String::from_utf8_lossy(&output.stdout); let stderr = String::from_utf8_lossy(&output.stderr); - info!("Redis stdout: {}", stdout); - info!("Redis stderr: {}", stderr); + if !stdout.is_empty() { + error!("Redis stderr: {}", stderr); + } if stderr.contains("NOAUTH") { - info!("Redis authentication failed (NOAUTH required)"); + error!("Redis authentication failed (NOAUTH required)"); return Ok(false); } if !output.status.success() { - info!("Redis command failed with status: {:?}", output.status); + error!("Redis command failed with status: {:?}", output.status); return Ok(false); } diff --git a/src/domain/valkey/ping.rs b/src/domain/valkey/ping.rs index 851c6a6..b3864da 100644 --- a/src/domain/valkey/ping.rs +++ b/src/domain/valkey/ping.rs @@ -2,7 +2,7 @@ use crate::services::config::DatabaseConfig; use anyhow::{Context, Result}; use tokio::process::Command; use tokio::time::{Duration, timeout}; -use tracing::{debug, info}; +use tracing::{debug, info, error}; pub async fn run(cfg: DatabaseConfig) -> Result { let mut cmd = Command::new("valkey-cli"); @@ -21,33 +21,34 @@ pub async fn run(cfg: DatabaseConfig) -> Result { cmd.arg("PING"); - debug!("Command Ping: {:?}", cmd); + debug!("Command Ping Valkey: {:?}", cmd); let result = timeout(Duration::from_secs(10), cmd.output()).await; match result { Ok(output) => { - let output = output.context("Failed to execute redis-cli")?; + let output = output.context("Failed to execute valkey-cli")?; let stdout = String::from_utf8_lossy(&output.stdout); let stderr = String::from_utf8_lossy(&output.stderr); - info!("Redis stdout: {}", stdout); - info!("Redis stderr: {}", stderr); + if !stdout.is_empty() { + error!("Valkey stderr: {}", stderr); + } if stderr.contains("NOAUTH") { - info!("Redis authentication failed (NOAUTH required)"); + error!("Valkey authentication failed (NOAUTH required)"); return Ok(false); } if !output.status.success() { - info!("Redis command failed with status: {:?}", output.status); + error!("Valkey command failed with status: {:?}", output.status); return Ok(false); } Ok(stdout.contains("PONG")) } Err(_) => { - info!("Timeout connecting to Redis at {}:{}", cfg.host, cfg.port); + info!("Timeout connecting to Valkey at {}:{}", cfg.host, cfg.port); Ok(false) } } diff --git a/src/settings.rs b/src/settings.rs index 03d47cf..053a115 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -25,6 +25,16 @@ impl Settings { .parse::() .expect("POOLING must be a valid positive integer"); + if pooling_seconds < 1 || pooling_seconds > 600 { + panic!("POOLING must be between 1 second and 600 seconds (10 minutes)"); + } + + if pooling_seconds < 5 { + eprintln!( + "[WARNING] POOLING is set to {}s. Values under 5s are not recommended for production.", + pooling_seconds + ); + } let tz = env::var("TZ").unwrap_or_else(|_| "UTC".to_string()); Self { From 1855c5120ac116ca74269ab06572346d2e52ef5c Mon Sep 17 00:00:00 2001 From: Charles GTE Date: Sat, 28 Mar 2026 16:44:07 +0100 Subject: [PATCH 3/3] fix: docker-compose.yml --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index ca3c860..7b19a5e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -21,7 +21,7 @@ services: LOG: debug TZ: "Europe/Paris" EDGE_KEY: "eyJzZXJ2ZXJVcmwiOiJodHRwOi8vbG9jYWxob3N0Ojg4ODciLCJhZ2VudElkIjoiNGI1OTM2MGItNTNkMi00ZTZmLWE1ODctODcyMmQ1NDc1MTNmIiwibWFzdGVyS2V5QjY0IjoiQlhWM1hvbEM2NTZTVjdkTmdjV1BHUWxrKytycExJNmxHRGk3Q1BCNWllbz0ifQ==" -# POOLING: 900 + #POOLING: 1 #DATABASES_CONFIG_FILE: "config.toml" extra_hosts: - "localhost:host-gateway"