From 24addb0a49ae3fe3f5e67688d262ddc2dff24d21 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Fri, 8 Aug 2025 01:26:40 -0400 Subject: [PATCH] track seconds elapsed since server startup --- .../endpoints/service/health_check_handler.rs | 12 +++++++++++- crates/service/web/storyteller_web/src/main.rs | 4 ++++ .../web/storyteller_web/src/state/server_state.rs | 4 ++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/service/health_check_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/service/health_check_handler.rs index 4ec7014312..9c227df29a 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/service/health_check_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/service/health_check_handler.rs @@ -4,7 +4,8 @@ use std::sync::Arc; use actix_web::error::ResponseError; use actix_web::http::StatusCode; use actix_web::{web, HttpRequest, HttpResponse}; -use chrono::NaiveDateTime; +use actix_web::web::Json; +use chrono::{DateTime, NaiveDateTime, Utc}; use log::error; use http_server_common::response::serialize_as_json_error::serialize_as_json_error; @@ -22,6 +23,8 @@ pub struct HealthCheckResponse { pub unhealthy_check_consecutive_count: Option, pub server_build_sha: String, pub server_hostname: String, + pub startup_time: DateTime, + pub seconds_since_startup: u64, } @@ -65,6 +68,11 @@ pub async fn get_health_check_handler( let is_healthy = health_check_status.is_healthy; + let now = Utc::now(); + let seconds_since_startup = now.signed_duration_since(server_state.startup_time) + .num_seconds() + .unsigned_abs(); + let response = HealthCheckResponse { success: true, is_healthy: health_check_status.is_healthy, @@ -73,6 +81,8 @@ pub async fn get_health_check_handler( unhealthy_check_consecutive_count: health_check_status.unhealthy_check_consecutive_count, server_build_sha: server_state.server_info.build_sha.clone(), server_hostname: server_state.hostname.clone(), + startup_time: server_state.startup_time, + seconds_since_startup, }; let body = serde_json::to_string(&response) diff --git a/crates/service/web/storyteller_web/src/main.rs b/crates/service/web/storyteller_web/src/main.rs index 3307e81a0a..bc12ed599d 100644 --- a/crates/service/web/storyteller_web/src/main.rs +++ b/crates/service/web/storyteller_web/src/main.rs @@ -25,6 +25,7 @@ use actix_multipart::form::MultipartFormConfig; use actix_web::middleware::{DefaultHeaders, Logger}; use actix_web::{middleware, web, App, HttpServer}; use anyhow::anyhow; +use chrono::Utc; use elasticsearch::http::transport::Transport; use elasticsearch::Elasticsearch; use log::info; @@ -392,6 +393,8 @@ async fn main() -> AnyhowResult<()> { let openai_api_key= easyenv::get_env_string_required("OPENAI_API_KEY")?; + let startup_time = Utc::now(); + let server_state = ServerState { env_config: EnvConfig { num_workers, @@ -409,6 +412,7 @@ async fn main() -> AnyhowResult<()> { client: stripe_client, }, hostname: server_hostname, + startup_time, server_environment_old: server_environment, server_environment: server_environment_typed, flags: service_feature_flags, diff --git a/crates/service/web/storyteller_web/src/state/server_state.rs b/crates/service/web/storyteller_web/src/state/server_state.rs index 95df8f8d44..e339c29bf8 100644 --- a/crates/service/web/storyteller_web/src/state/server_state.rs +++ b/crates/service/web/storyteller_web/src/state/server_state.rs @@ -1,3 +1,4 @@ +use chrono::{DateTime, Utc}; use elasticsearch::Elasticsearch; use r2d2_redis::{r2d2, RedisConnectionManager}; use sqlx::MySqlPool; @@ -51,6 +52,9 @@ pub struct ServerState { pub hostname: String, + /// When the server starts. + pub startup_time: DateTime, + #[deprecated(note = "Use `server_environment` instead")] /// Knowing if we're in production will allow us to turn off development-only functionalities. pub server_environment_old: ServerEnvironment,