Skip to content

Commit b09df84

Browse files
committed
docs: update CHANGELOG with new readiness checks and methods in Rust client
feat(health): add `readyz()` and `is_ready()` methods to Rust `HealthClient` feat(health): introduce `ReadinessStatus` enum for Rust client refactor: update Rust client example to demonstrate liveness and readiness checks
1 parent 807e8b7 commit b09df84

File tree

6 files changed

+67
-15
lines changed

6 files changed

+67
-15
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1616
- Added aggregator block production rate check to `/health/ready` endpoint to ensure aggregators are producing blocks within expected timeframe (5x block time) ([#2800](https://github.com/evstack/ev-node/pull/2800))
1717
- Added `GetReadiness()` method to Go RPC client for checking `/health/ready` endpoint ([#2800](https://github.com/evstack/ev-node/pull/2800))
1818
- Added `ReadinessStatus` type to Go RPC client with READY/UNREADY/UNKNOWN states ([#2800](https://github.com/evstack/ev-node/pull/2800))
19+
- Added `readyz()` and `is_ready()` methods to Rust `HealthClient` for checking `/health/ready` endpoint ([#2800](https://github.com/evstack/ev-node/pull/2800))
20+
- Added `ReadinessStatus` enum to Rust client with Ready/Unready/Unknown states ([#2800](https://github.com/evstack/ev-node/pull/2800))
1921

2022
### Changed
2123

2224
- Use cache instead of in memory store for reaper. Persist cache on reload. Autoclean after 24 hours. ([#2811](https://github.com/evstack/ev-node/pull/2811))
2325
- Simplified `/health/live` endpoint to only check store accessibility (liveness) instead of business logic, following Kubernetes best practices ([#2800](https://github.com/evstack/ev-node/pull/2800))
2426
- Updated `/health/ready` endpoint to use `GetState()` instead of `Height()` to access block production timing information ([#2800](https://github.com/evstack/ev-node/pull/2800))
2527
- Renamed integration test from `TestHealthEndpointWhenBlockProductionStops` to `TestReadinessEndpointWhenBlockProductionStops` to correctly test readiness endpoint ([#2800](https://github.com/evstack/ev-node/pull/2800))
28+
- Updated Rust client example (`client/crates/client/examples/basic.rs`) to demonstrate both liveness and readiness checks ([#2800](https://github.com/evstack/ev-node/pull/2800))
2629

2730
### Removed
2831

client/crates/client/examples/basic.rs

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use ev_client::{Client, HealthClient, P2PClient, StoreClient};
1+
use ev_client::{health::HealthClient, Client, P2PClient, StoreClient};
22
use std::error::Error;
33

44
#[tokio::main]
@@ -14,15 +14,26 @@ async fn main() -> Result<(), Box<dyn Error>> {
1414
let client = Client::connect(&endpoint).await?;
1515
println!("Successfully connected to evolve node");
1616

17-
// Check health status
17+
// Check health status (HTTP endpoints)
1818
println!("\n=== Health Check ===");
19-
let health = HealthClient::new(&client);
20-
match health.get_health().await {
21-
Ok(health_response) => {
22-
println!("Health status: {:?}", health_response.status());
23-
println!("Node is healthy: {}", health.is_healthy().await?);
19+
let health = HealthClient::with_base_url(endpoint.clone());
20+
21+
// Liveness check - is the process alive?
22+
match health.livez().await {
23+
Ok(status) => {
24+
println!("Liveness status: {:?}", status);
25+
println!("Node is alive: {}", health.is_healthy().await?);
26+
}
27+
Err(e) => println!("Failed to get liveness status: {e}"),
28+
}
29+
30+
// Readiness check - can it serve correct data?
31+
match health.readyz().await {
32+
Ok(status) => {
33+
println!("Readiness status: {:?}", status);
34+
println!("Node is ready: {}", health.is_ready().await?);
2435
}
25-
Err(e) => println!("Failed to get health status: {e}"),
36+
Err(e) => println!("Failed to get readiness status: {e}"),
2637
}
2738

2839
// Get P2P information

client/crates/client/src/health.rs

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{client::Client, error::Result};
22

3-
/// Health status of the node
3+
/// Health status of the node (liveness check)
44
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55
pub enum HealthStatus {
66
/// Node is operating normally
@@ -13,6 +13,17 @@ pub enum HealthStatus {
1313
Unknown,
1414
}
1515

16+
/// Readiness status of the node (can serve correct data)
17+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18+
pub enum ReadinessStatus {
19+
/// Node is ready to serve traffic
20+
Ready,
21+
/// Node is not ready to serve traffic
22+
Unready,
23+
/// Unknown readiness status
24+
Unknown,
25+
}
26+
1627
pub struct HealthClient {
1728
base_url: String,
1829
http_client: reqwest::Client,
@@ -37,7 +48,10 @@ impl HealthClient {
3748
}
3849
}
3950

40-
/// Check if the node is alive and get its health status
51+
/// Check if the node is alive and get its health status (liveness check)
52+
///
53+
/// This endpoint checks if the process is alive and responsive.
54+
/// A failing liveness check should result in killing/restarting the process.
4155
pub async fn livez(&self) -> Result<HealthStatus> {
4256
let url = format!("{}/health/live", self.base_url);
4357
let response = self.http_client.get(&url).send().await?;
@@ -52,9 +66,35 @@ impl HealthClient {
5266
}
5367
}
5468

55-
/// Check if the node is healthy (status is PASS)
69+
/// Check if the node is ready to serve correct data (readiness check)
70+
///
71+
/// This endpoint checks if the node can serve correct data to clients.
72+
/// A failing readiness check should remove the node from load balancer
73+
/// but NOT kill the process.
74+
pub async fn readyz(&self) -> Result<ReadinessStatus> {
75+
let url = format!("{}/health/ready", self.base_url);
76+
let response = self.http_client.get(&url).send().await?;
77+
78+
let status_text = response.text().await?.trim().to_string();
79+
80+
if status_text.starts_with("READY") {
81+
Ok(ReadinessStatus::Ready)
82+
} else if status_text.starts_with("UNREADY") {
83+
Ok(ReadinessStatus::Unready)
84+
} else {
85+
Ok(ReadinessStatus::Unknown)
86+
}
87+
}
88+
89+
/// Check if the node is healthy (liveness status is PASS)
5690
pub async fn is_healthy(&self) -> Result<bool> {
5791
let status = self.livez().await?;
5892
Ok(status == HealthStatus::Pass)
5993
}
94+
95+
/// Check if the node is ready (readiness status is READY)
96+
pub async fn is_ready(&self) -> Result<bool> {
97+
let status = self.readyz().await?;
98+
Ok(status == ReadinessStatus::Ready)
99+
}
60100
}

client/crates/client/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ pub mod store;
8888
pub use client::{Client, ClientBuilder};
8989
pub use config::ConfigClient;
9090
pub use error::{ClientError, Result};
91-
pub use health::HealthClient;
91+
pub use health::{HealthClient, HealthStatus, ReadinessStatus};
9292
pub use p2p::P2PClient;
9393
pub use signer::SignerClient;
9494
pub use store::StoreClient;

client/crates/types/tests/feature_test.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,11 @@ fn test_message_types_available() {
1010
#[test]
1111
fn test_grpc_types_available() {
1212
// These should only be available with the grpc feature
13-
use ev_types::v1::health_service_client::HealthServiceClient;
1413
use ev_types::v1::p2p_service_client::P2pServiceClient;
1514
use ev_types::v1::signer_service_client::SignerServiceClient;
1615
use ev_types::v1::store_service_client::StoreServiceClient;
1716

1817
// Just verify the types exist
19-
let _ = std::any::type_name::<HealthServiceClient<tonic::transport::Channel>>();
2018
let _ = std::any::type_name::<P2pServiceClient<tonic::transport::Channel>>();
2119
let _ = std::any::type_name::<SignerServiceClient<tonic::transport::Channel>>();
2220
let _ = std::any::type_name::<StoreServiceClient<tonic::transport::Channel>>();

pkg/rpc/client/client_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import (
2626

2727
// setupTestServerOptions holds optional parameters for setupTestServer
2828
type setupTestServerOptions struct {
29-
config *config.Config
29+
config *config.Config
3030
bestKnownHeightProvider server.BestKnownHeightProvider
3131
}
3232

0 commit comments

Comments
 (0)