100 lines
3.3 KiB
Rust
100 lines
3.3 KiB
Rust
use std::time::Instant;
|
|
|
|
use actix_web::dev::Service;
|
|
use actix_web::{App, HttpResponse, HttpServer, dev::Server, web};
|
|
use cache::AppCache;
|
|
use db::database::AppDatabase;
|
|
|
|
const REQUEST_LOG_EXCLUDED_PATHS: &[&str] = &[
|
|
"/health",
|
|
"/live",
|
|
"/ready",
|
|
"/metrics",
|
|
"/favicon.ico",
|
|
"/robots.txt",
|
|
];
|
|
|
|
fn should_log_request(path: &str) -> bool {
|
|
!REQUEST_LOG_EXCLUDED_PATHS.contains(&path)
|
|
}
|
|
|
|
async fn health(
|
|
db: web::Data<AppDatabase>,
|
|
cache: web::Data<AppCache>,
|
|
) -> HttpResponse {
|
|
let db_ok = sqlx::query("SELECT 1").execute(db.reader()).await.is_ok();
|
|
let cache_ok = cache.ping_cluster().await.is_ok();
|
|
|
|
if db_ok && cache_ok {
|
|
HttpResponse::Ok().json(serde_json::json!({
|
|
"status": "ok",
|
|
"db": "ok",
|
|
"cache": "ok",
|
|
}))
|
|
} else {
|
|
HttpResponse::ServiceUnavailable().json(serde_json::json!({
|
|
"status": "unhealthy",
|
|
"db": if db_ok { "ok" } else { "error" },
|
|
"cache": if cache_ok { "ok" } else { "error" },
|
|
}))
|
|
}
|
|
}
|
|
|
|
pub fn start_health(
|
|
port: u16,
|
|
db: AppDatabase,
|
|
cache: AppCache,
|
|
) -> anyhow::Result<Server> {
|
|
tracing::info!("health endpoint starting on 0.0.0.0:{}", port);
|
|
|
|
let srv = HttpServer::new(move || {
|
|
App::new()
|
|
.app_data(web::Data::new(db.clone()))
|
|
.app_data(web::Data::new(cache.clone()))
|
|
.wrap_fn(|req, srv| {
|
|
let should_log = should_log_request(req.path());
|
|
let method = req.method().clone();
|
|
let path = req.path().to_owned();
|
|
let peer_addr =
|
|
req.connection_info().peer_addr().map(str::to_owned);
|
|
let started_at = Instant::now();
|
|
let fut = srv.call(req);
|
|
|
|
async move {
|
|
match fut.await {
|
|
Ok(res) => {
|
|
if should_log {
|
|
tracing::info!(
|
|
method = %method,
|
|
path = %path,
|
|
status = res.status().as_u16(),
|
|
elapsed_ms = started_at.elapsed().as_millis(),
|
|
peer_addr = peer_addr.as_deref().unwrap_or("-"),
|
|
"http request"
|
|
);
|
|
}
|
|
Ok(res)
|
|
}
|
|
Err(err) => {
|
|
if should_log {
|
|
tracing::warn!(
|
|
method = %method,
|
|
path = %path,
|
|
elapsed_ms = started_at.elapsed().as_millis(),
|
|
peer_addr = peer_addr.as_deref().unwrap_or("-"),
|
|
error = %err,
|
|
"http request failed"
|
|
);
|
|
}
|
|
Err(err)
|
|
}
|
|
}
|
|
}
|
|
})
|
|
.route("/health", web::get().to(health))
|
|
})
|
|
.bind(format!("0.0.0.0:{}", port))?;
|
|
|
|
Ok(srv.run())
|
|
}
|