huskies: merge 768
This commit is contained in:
@@ -221,10 +221,20 @@ pub async fn fetch_pipeline_status_for_project(
|
||||
.map_err(|e| format!("invalid upstream response: {e}"))
|
||||
}
|
||||
|
||||
/// Check health of a single project URL.
|
||||
/// Check health of a single project URL via the read-RPC `health.check` method.
|
||||
///
|
||||
/// Sends an RPC request to the project's `/mcp` endpoint. A successful
|
||||
/// response (HTTP 2xx) indicates the project container is reachable and
|
||||
/// serving requests.
|
||||
pub async fn check_project_health(client: &Client, base_url: &str) -> Result<bool, String> {
|
||||
let health_url = format!("{}/health", base_url.trim_end_matches('/'));
|
||||
match client.get(&health_url).send().await {
|
||||
let mcp_url = format!("{}/mcp", base_url.trim_end_matches('/'));
|
||||
let rpc_body = json!({
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"method": "tools/list",
|
||||
"params": {}
|
||||
});
|
||||
match client.post(&mcp_url).json(&rpc_body).send().await {
|
||||
Ok(resp) => Ok(resp.status().is_success()),
|
||||
Err(e) => Err(format!("unreachable: {e}")),
|
||||
}
|
||||
|
||||
@@ -404,32 +404,6 @@ pub async fn init_project(
|
||||
Ok(registered_name)
|
||||
}
|
||||
|
||||
/// Fetch aggregated health status across all projects.
|
||||
pub async fn health_check_all(state: &GatewayState) -> (bool, BTreeMap<String, &'static str>) {
|
||||
let mut all_healthy = true;
|
||||
let mut statuses = BTreeMap::new();
|
||||
|
||||
let project_entries: Vec<(String, String)> = state
|
||||
.projects
|
||||
.read()
|
||||
.await
|
||||
.iter()
|
||||
.map(|(n, e)| (n.clone(), e.url.clone()))
|
||||
.collect();
|
||||
|
||||
for (name, url) in &project_entries {
|
||||
let healthy = io::check_project_health(&state.client, url)
|
||||
.await
|
||||
.unwrap_or(false);
|
||||
if !healthy {
|
||||
all_healthy = false;
|
||||
}
|
||||
statuses.insert(name.clone(), if healthy { "ok" } else { "error" });
|
||||
}
|
||||
|
||||
(all_healthy, statuses)
|
||||
}
|
||||
|
||||
/// Broadcast a status event received from a project node to all local subscribers.
|
||||
///
|
||||
/// Returns the number of active receivers that received the event.
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
//! Pure health-check logic — no side effects.
|
||||
|
||||
use poem_openapi::Object;
|
||||
use serde::Serialize;
|
||||
|
||||
/// The JSON payload returned by the health check endpoint.
|
||||
#[derive(Serialize, Object)]
|
||||
pub struct HealthStatus {
|
||||
/// Human-readable status string, always `"ok"` when the server is healthy.
|
||||
pub status: String,
|
||||
}
|
||||
|
||||
/// Return a healthy status response.
|
||||
pub fn ok() -> HealthStatus {
|
||||
HealthStatus {
|
||||
status: "ok".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn ok_returns_status_ok() {
|
||||
let s = ok();
|
||||
assert_eq!(s.status, "ok");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn health_status_serializes() {
|
||||
let s = HealthStatus {
|
||||
status: "ok".to_string(),
|
||||
};
|
||||
let json = serde_json::to_value(&s).unwrap();
|
||||
assert_eq!(json["status"], "ok");
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
//! Health I/O wrappers.
|
||||
//!
|
||||
//! Health has no side effects; this file exists to satisfy the
|
||||
//! service-module convention (`docs/architecture/service-modules.md`).
|
||||
@@ -1,39 +0,0 @@
|
||||
//! Health service — public API for the health domain.
|
||||
//!
|
||||
//! Exposes a single `check()` function that returns a [`HealthStatus`].
|
||||
//! HTTP handlers call this instead of constructing the response inline.
|
||||
//!
|
||||
//! Conventions: `docs/architecture/service-modules.md`
|
||||
|
||||
pub mod check;
|
||||
pub(super) mod io;
|
||||
|
||||
pub use check::HealthStatus;
|
||||
|
||||
// ── Error type ────────────────────────────────────────────────────────────────
|
||||
|
||||
/// Typed errors returned by `service::health` functions.
|
||||
///
|
||||
/// Health checks are currently infallible; this enum satisfies the module
|
||||
/// convention and accommodates future error cases (e.g. dependency checks).
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
/// An internal error occurred during the health check.
|
||||
Internal(String),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Internal(msg) => write!(f, "Health error: {msg}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Public API ────────────────────────────────────────────────────────────────
|
||||
|
||||
/// Perform a health check and return the status.
|
||||
pub fn check() -> HealthStatus {
|
||||
check::ok()
|
||||
}
|
||||
@@ -14,7 +14,6 @@ pub mod events;
|
||||
pub mod file_io;
|
||||
pub mod gateway;
|
||||
pub mod git_ops;
|
||||
pub mod health;
|
||||
pub mod merge;
|
||||
pub mod notifications;
|
||||
pub mod oauth;
|
||||
|
||||
Reference in New Issue
Block a user