Skip to content

Commit 2b0ffee

Browse files
0xf1esnowpoke
andauthored
fix(health): Correctly implement spec for overall health (#897)
Co-authored-by: snowpoke <[email protected]>
1 parent d574cfd commit 2b0ffee

File tree

1 file changed

+43
-15
lines changed

1 file changed

+43
-15
lines changed

tonic-health/src/server.rs

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@ pub struct HealthReporter {
4040

4141
impl HealthReporter {
4242
fn new() -> Self {
43-
let statuses = Arc::new(RwLock::new(HashMap::new()));
43+
// According to the gRPC Health Check specification, the empty service "" corresponds to the overall server health
44+
let server_status = ("".to_string(), watch::channel(ServingStatus::Serving));
45+
46+
let statuses = Arc::new(RwLock::new(HashMap::from([server_status])));
4447

4548
HealthReporter { statuses }
4649
}
@@ -166,9 +169,7 @@ mod tests {
166169
use crate::proto::HealthCheckRequest;
167170
use crate::server::{HealthReporter, HealthService};
168171
use crate::ServingStatus;
169-
use std::collections::HashMap;
170-
use std::sync::Arc;
171-
use tokio::sync::{watch, RwLock};
172+
use tokio::sync::watch;
172173
use tokio_stream::StreamExt;
173174
use tonic::{Code, Request, Status};
174175

@@ -183,23 +184,35 @@ mod tests {
183184
}
184185

185186
async fn make_test_service() -> (HealthReporter, HealthService) {
186-
let state = Arc::new(RwLock::new(HashMap::new()));
187-
state.write().await.insert(
188-
"TestService".to_string(),
189-
watch::channel(ServingStatus::Unknown),
190-
);
191-
(
192-
HealthReporter {
193-
statuses: state.clone(),
194-
},
195-
HealthService::new(state.clone()),
196-
)
187+
let health_reporter = HealthReporter::new();
188+
189+
// insert test value
190+
{
191+
let mut statuses = health_reporter.statuses.write().await;
192+
statuses.insert(
193+
"TestService".to_string(),
194+
watch::channel(ServingStatus::Unknown),
195+
);
196+
}
197+
198+
let health_service = HealthService::new(health_reporter.statuses.clone());
199+
(health_reporter, health_service)
197200
}
198201

199202
#[tokio::test]
200203
async fn test_service_check() {
201204
let (mut reporter, service) = make_test_service().await;
202205

206+
// Overall server health
207+
let resp = service
208+
.check(Request::new(HealthCheckRequest {
209+
service: "".to_string(),
210+
}))
211+
.await;
212+
assert!(resp.is_ok());
213+
let resp = resp.unwrap().into_inner();
214+
assert_serving_status(resp.status, ServingStatus::Serving);
215+
203216
// Unregistered service
204217
let resp = service
205218
.check(Request::new(HealthCheckRequest {
@@ -237,6 +250,21 @@ mod tests {
237250
async fn test_service_watch() {
238251
let (mut reporter, service) = make_test_service().await;
239252

253+
// Overall server health
254+
let resp = service
255+
.watch(Request::new(HealthCheckRequest {
256+
service: "".to_string(),
257+
}))
258+
.await;
259+
assert!(resp.is_ok());
260+
let mut resp = resp.unwrap().into_inner();
261+
let item = resp
262+
.next()
263+
.await
264+
.expect("streamed response is Some")
265+
.expect("response is ok");
266+
assert_serving_status(item.status, ServingStatus::Serving);
267+
240268
// Unregistered service
241269
let resp = service
242270
.watch(Request::new(HealthCheckRequest {

0 commit comments

Comments
 (0)