-
Notifications
You must be signed in to change notification settings - Fork 1
feat: add-heathcheck-database #48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -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<bool> { | ||||||||||||||
| let mut cmd = Command::new("redis-cli"); | ||||||||||||||
|
|
@@ -21,7 +21,7 @@ pub async fn run(cfg: DatabaseConfig) -> Result<bool> { | |||||||||||||
|
|
||||||||||||||
| 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<bool> { | |||||||||||||
| 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); | ||||||||||||||
| } | ||||||||||||||
|
Comment on lines
+34
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Line 34 checks 🩹 Suggested fix- if !stdout.is_empty() {
+ if !stderr.is_empty() {
error!("Redis stderr: {}", stderr);
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||
|
|
||||||||||||||
| 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); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
|
|
||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -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<bool> { | ||||||||||||||
| let mut cmd = Command::new("valkey-cli"); | ||||||||||||||
|
|
@@ -21,33 +21,34 @@ pub async fn run(cfg: DatabaseConfig) -> Result<bool> { | |||||||||||||
|
|
||||||||||||||
| cmd.arg("PING"); | ||||||||||||||
|
|
||||||||||||||
| debug!("Command Ping: {:?}", cmd); | ||||||||||||||
| debug!("Command Ping Valkey: {:?}", cmd); | ||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: find . -name "ping.rs" -path "*/valkey/*" | head -5Repository: Portabase/agent Length of output: 86 🏁 Script executed: cat -n ./src/domain/valkey/ping.rsRepository: Portabase/agent Length of output: 2016 🏁 Script executed: find . -name "Cargo.toml" -type f | head -1 | xargs cat | grep -A 20 "dependencies"Repository: Portabase/agent Length of output: 1125 🌐 Web query:
💡 Result: The tokio::process::Command struct implements the Debug trait. This has been present at least since early versions like 1.8.0 and continues in the latest versions (1.50.0 as of 2026-03-03). In Tokio 1.49.0, a fix was made to "remove unnecessary trait bounds on the Debug implementation" for tasks, but the Command Debug impl itself is standard and derives from its fields, including the underlying std::process::Command (which shows program and arguments) and the kill_on_drop flag. The Debug output typically displays the configured program name, arguments, environment variables, working directory, and other settings from the wrapped std::process::Command, plus Tokio-specific fields like kill_on_drop. Citations:
Redact credentials from the debug command log. Line 24 logs the full command using 🔐 Safer logging- debug!("Command Ping Valkey: {:?}", cmd);
+ debug!("Running Valkey ping against {}:{}", cfg.host, cfg.port);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||
|
|
||||||||||||||
| 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); | ||||||||||||||
| } | ||||||||||||||
|
Comment on lines
+34
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Line 34 checks 🩹 Suggested fix- if !stdout.is_empty() {
+ if !stderr.is_empty() {
error!("Valkey stderr: {}", stderr);
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||
|
|
||||||||||||||
| 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) | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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<Context>, | ||
|
|
@@ -25,14 +27,20 @@ impl StatusService { | |
| pub async fn ping(&self, databases: &[DatabaseConfig]) -> Result<PingResult, Box<dyn Error>> { | ||
| let edge_key = &self.ctx.edge_key; | ||
|
|
||
| let databases_payload: Vec<DatabasePayload> = databases | ||
| .iter() | ||
| .map(|db| DatabasePayload { | ||
| name: &db.name, | ||
| dbms: &db.db_type.as_str(), | ||
| generated_id: &db.generated_id, | ||
| let databases_payload: Vec<DatabasePayload> = 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, anyhow::Error>(DatabasePayload { | ||
| name: &db.name, | ||
| dbms: &db.db_type.as_str(), | ||
| generated_id: &db.generated_id, | ||
| ping_status: reachable, | ||
| }) | ||
| }) | ||
| .collect(); | ||
| ).await?; | ||
|
Comment on lines
+30
to
+43
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # First, let's find and examine the status.rs file
find . -name "status.rs" -path "*/services/*" | head -5Repository: Portabase/agent Length of output: 229 🏁 Script executed: # Look for ping.rs files in domain subdirectories
find . -name "ping.rs" -path "*/domain/*" | head -10Repository: Portabase/agent Length of output: 227 🏁 Script executed: # Check the repository structure
ls -la src/ 2>/dev/null | head -20Repository: Portabase/agent Length of output: 620 🏁 Script executed: # Read the status.rs file to see lines 30-43 and the import at line 11
cat -n src/services/status.rs | head -50Repository: Portabase/agent Length of output: 1973 🏁 Script executed: # Read redis/ping.rs around line 30
cat -n src/domain/redis/ping.rs | head -40Repository: Portabase/agent Length of output: 1528 🏁 Script executed: # Read valkey/ping.rs around line 30
cat -n src/domain/valkey/ping.rs | head -40Repository: Portabase/agent Length of output: 1533 🏁 Script executed: # Check a couple other ping implementations to see if pattern is consistent
cat -n src/domain/mysql/ping.rs | head -40Repository: Portabase/agent Length of output: 955 🏁 Script executed: # Check how the ping result is used in the context
cat -n src/services/status.rs | tail -20Repository: Portabase/agent Length of output: 767 🏁 Script executed: # Search for callers of the StatusService::ping method
rg "StatusService::ping|\.ping\(" src/services/ -A 3 -B 1Repository: Portabase/agent Length of output: 897 One ping error should not abort the entire status report. Line 30–43 uses Other services in this codebase ( 🩹 Suggested approach- let databases_payload: Vec<DatabasePayload> = try_join_all(
+ let databases_payload: Vec<DatabasePayload> = 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, anyhow::Error>(DatabasePayload {
+ let reachable = match db_engine.ping().await {
+ Ok(reachable) => reachable,
+ Err(err) => {
+ tracing::error!(database = %db.name, error = ?err, "Database ping failed");
+ false
+ }
+ };
+
+ DatabasePayload {
name: &db.name,
dbms: &db.db_type.as_str(),
generated_id: &db.generated_id,
ping_status: reachable,
- })
+ }
})
- ).await?;
+ ).await;Update line 11 to import 🤖 Prompt for AI Agents |
||
|
|
||
| let version_str = CONFIG.app_version.as_str(); | ||
| let result = self | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: Portabase/agent
Length of output: 2009
Redact credentials from the debug command log.
Line 24 logs the full
tokio::process::Commandafter line 19 appends the password with the-aflag. Sincetokio::process::Command's Debug output includes all arguments, this will expose Redis credentials in debug logs.🔐 Safer logging
📝 Committable suggestion
🤖 Prompt for AI Agents