Health checks
Roadster allows registering
HealthCheck
s to ensure server
instances are functioning as expected. Roadster provides some default health checks that simply check that the server's
dependencies (e.g., DB and Redis) are accessible. All health checks -- both the defaults and any custom ones registered
for an app -- run on app startup, via the CLI, and in the API at /api/_health
. The route of this API is configurable
via the service.http.default-routes.health.route
config field.
Roadster also provides the /api/_ping
API, which simply returns a successful HTTP status (200) and does no
other work.
Custom HealthCheck
To provide a custom health check, implement the
HealthCheck
trait and register the
check when building the app. Note that if the check requires access to the app's state, it should be provided via a
Weak
reference to the state. This is because health checks
are stored in Roadster's AppContext
,
which introduces a circular reference between the context and health checks. A weak reference to AppContext
can be
retrieved via
AppContext#downgrade
.
Implement HealthCheck
pub struct ExampleCheck {
state: AppContextWeak,
}
impl ExampleCheck {
pub fn new(state: &AppContext) -> Self {
Self {
state: state.downgrade(),
}
}
}
#[async_trait]
impl HealthCheck for ExampleCheck {
fn name(&self) -> String {
"example".to_string()
}
fn enabled(&self) -> bool {
// Custom health checks can be enabled/disabled via the app config
// just like built-in checks
if let Some(state) = self.state.upgrade() {
state
.config()
.health_check
.custom
.get(&self.name())
.map(|config| config.common.enabled(&state))
.unwrap_or_else(|| state.config().health_check.default_enable)
} else {
false
}
}
async fn check(&self) -> RoadsterResult<CheckResponse> {
Ok(CheckResponse::builder()
.status(Status::Ok)
.latency(Duration::from_secs(0))
.build())
}
}
Register custom HealthCheck
fn build_app() -> RoadsterApp<AppContext> {
RoadsterApp::builder()
// Use the default `AppContext` for this example
.state_provider(|context| Ok(context))
// Register custom health check(s)
.add_health_check_provider(|registry, state| {
registry.register(ExampleCheck::new(state))?;
Ok(())
})
.add_service_provider(move |_registry, _state| {
Box::pin(async move { todo!("Add services here.") })
})
.build()
}