diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 4f6c80a468c..bb0e356c816 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -76,6 +76,9 @@ The CI checks require `cargo-deny` and `cargo-about` which can both be installed - `cargo install cargo-deny` - `cargo install cargo-about` +Updating the snapshots used during testing requires installing `cargo-insta`: +- `cargo install cargo-insta` + They also need you to have the federation-demo project up and running, as explained in the Getting started section above. diff --git a/apollo-router/src/axum_factory/axum_http_server_factory.rs b/apollo-router/src/axum_factory/axum_http_server_factory.rs index 1373586dece..946724bc3dd 100644 --- a/apollo-router/src/axum_factory/axum_http_server_factory.rs +++ b/apollo-router/src/axum_factory/axum_http_server_factory.rs @@ -103,13 +103,14 @@ where if configuration.health_check.enabled { tracing::info!( - "Health check endpoint exposed at {}/health", - configuration.health_check.listen + "Health check endpoint exposed at {}/{}", + configuration.health_check.listen, + configuration.health_check.endpoint ); endpoints.insert( configuration.health_check.listen.clone(), Endpoint::from_router_service( - "/health".to_string(), + configuration.health_check.endpoint.clone(), service_fn(move |req: router::Request| { let mut status_code = StatusCode::OK; let health = if let Some(query) = req.router_request.uri().query() { diff --git a/apollo-router/src/configuration/mod.rs b/apollo-router/src/configuration/mod.rs index d1eb9bef9fc..9758c104df4 100644 --- a/apollo-router/src/configuration/mod.rs +++ b/apollo-router/src/configuration/mod.rs @@ -1163,23 +1163,41 @@ pub(crate) struct HealthCheck { /// Set to false to disable the health check endpoint pub(crate) enabled: bool, + + /// Optionally set a custom healthcheck endpoint + /// Defaults to /health + pub(crate) endpoint: String, } fn default_health_check_listen() -> ListenAddr { SocketAddr::from_str("127.0.0.1:8088").unwrap().into() } -fn default_health_check() -> bool { +fn default_health_check_enabled() -> bool { true } +fn default_health_check_endpoint() -> String { + "/health".to_string() +} + #[buildstructor::buildstructor] impl HealthCheck { #[builder] - pub(crate) fn new(listen: Option, enabled: Option) -> Self { + pub(crate) fn new( + listen: Option, + enabled: Option, + endpoint: Option, + ) -> Self { + let mut endpoint = endpoint.unwrap_or_else(default_health_check_endpoint); + if !endpoint.starts_with('/') { + endpoint = format!("/{endpoint}").to_string(); + } + Self { listen: listen.unwrap_or_else(default_health_check_listen), - enabled: enabled.unwrap_or_else(default_health_check), + enabled: enabled.unwrap_or_else(default_health_check_enabled), + endpoint, } } } @@ -1188,10 +1206,15 @@ impl HealthCheck { #[buildstructor::buildstructor] impl HealthCheck { #[builder] - pub(crate) fn fake_new(listen: Option, enabled: Option) -> Self { + pub(crate) fn fake_new( + listen: Option, + enabled: Option, + endpoint: Option, + ) -> Self { Self { listen: listen.unwrap_or_else(test_listen), - enabled: enabled.unwrap_or_else(default_health_check), + enabled: enabled.unwrap_or_else(default_health_check_enabled), + endpoint: endpoint.unwrap_or_else(default_health_check_endpoint), } } } diff --git a/apollo-router/src/configuration/snapshots/apollo_router__configuration__tests__schema_generation.snap b/apollo-router/src/configuration/snapshots/apollo_router__configuration__tests__schema_generation.snap index 73498d68bc6..2d811ad56a7 100644 --- a/apollo-router/src/configuration/snapshots/apollo_router__configuration__tests__schema_generation.snap +++ b/apollo-router/src/configuration/snapshots/apollo_router__configuration__tests__schema_generation.snap @@ -1557,7 +1557,8 @@ expression: "&schema" "description": "Health check configuration", "default": { "listen": "127.0.0.1:8088", - "enabled": true + "enabled": true, + "endpoint": "/health" }, "type": "object", "properties": { @@ -1566,6 +1567,11 @@ expression: "&schema" "default": true, "type": "boolean" }, + "endpoint": { + "description": "Optionally set a custom healthcheck endpoint Defaults to /health", + "default": "/health", + "type": "string" + }, "listen": { "description": "The socket address and port to listen on Defaults to 127.0.0.1:8088", "default": "127.0.0.1:8088", diff --git a/apollo-router/src/configuration/tests.rs b/apollo-router/src/configuration/tests.rs index db6f317d53a..507e2d5293e 100644 --- a/apollo-router/src/configuration/tests.rs +++ b/apollo-router/src/configuration/tests.rs @@ -934,6 +934,39 @@ fn test_deserialize_derive_default() { } } +#[test] +fn it_defaults_health_check_configuration() { + let conf = Configuration::default(); + let addr: ListenAddr = SocketAddr::from_str("127.0.0.1:8088").unwrap().into(); + + assert_eq!(conf.health_check.listen, addr); + assert_eq!(&conf.health_check.endpoint, "/health"); + + // Defaults to enabled: true + assert!(conf.health_check.enabled); +} + +#[test] +fn it_sets_custom_health_check_endpoint() { + let conf = Configuration::builder() + .health_check(HealthCheck::new(None, None, Some("/healthz".to_string()))) + .build() + .unwrap(); + + assert_eq!(&conf.health_check.endpoint, "/healthz"); +} + +#[test] +fn it_adds_slash_to_custom_health_check_endpoint_if_missing() { + let conf = Configuration::builder() + // NB the missing `/` + .health_check(HealthCheck::new(None, None, Some("healthz".to_string()))) + .build() + .unwrap(); + + assert_eq!(&conf.health_check.endpoint, "/healthz"); +} + fn has_field_level_serde_defaults(lines: &[&str], line_number: usize) -> bool { let serde_field_default = Regex::new( r#"^\s*#[\s\n]*\[serde\s*\((.*,)?\s*default\s*=\s*"[a-zA-Z0-9_:]+"\s*(,.*)?\)\s*\]\s*$"#, diff --git a/docs/source/configuration/health-checks.mdx b/docs/source/configuration/health-checks.mdx index 26ba5b80bcd..ed8f309ed90 100644 --- a/docs/source/configuration/health-checks.mdx +++ b/docs/source/configuration/health-checks.mdx @@ -11,6 +11,23 @@ You can change this by setting `health_check`: health_check: listen: 127.0.0.1:8088 enabled: true + endpoint: /health +``` + +Each option is configurable. For example, we might want to set our health check to `127.0.0.1:8090/healthz`: + +```yaml title="router.yaml" +health_check: + listen: 127.0.0.1:8090 + enabled: true + endpoint: /healthz +``` + +We can also disable the health check: + +```yaml title="router.yaml" +health_check: + enabled: false ``` ## Testing with `curl`