Skip to content

Commit

Permalink
feat(rover): use router healthcheck endpoint (#1939)
Browse files Browse the repository at this point in the history
This changes how Rover infers Apollo Router readiness by using the
`/health?ready` endpoint instead of using a `query { __typename }`
query.
  • Loading branch information
nmoutschen authored Jun 21, 2024
1 parent b8f6fce commit 74eb9d7
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 9 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ url = { workspace = true, features = ["serde"] }
assert_cmd = { workspace = true }
assert_fs = { workspace = true }
assert-json-diff = { workspace = true }
httpmock = { workspace = true }
predicates = { workspace = true }
reqwest = { workspace = true, features = ["blocking", "native-tls-vendored"] }
rstest = { workspace = true }
Expand Down
72 changes: 63 additions & 9 deletions src/command/dev/router/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,12 @@ impl RouterRunner {
let now = Instant::now();
let seconds = 10;
let base_url = format!(
"http://{}{}",
"http://{}{}/health?ready",
&self.router_socket_addr, &self.router_listen_path
);
let mut endpoint =
Url::parse(&base_url).with_context(|| format!("{base_url} is not a valid URL."))?;
endpoint.set_query(Some("query={__typename}"));
let endpoint = endpoint.to_string();
let endpoint = Url::parse(&base_url)
.with_context(|| format!("{base_url} is not a valid URL."))?
.to_string();
while !ready && now.elapsed() < Duration::from_secs(seconds) {
let _ = client
.get(&endpoint)
Expand Down Expand Up @@ -143,10 +142,7 @@ impl RouterRunner {
let seconds = 5;
while ready && now.elapsed() < Duration::from_secs(seconds) {
let _ = client
.get(format!(
"http://{}/?query={{__typename}}",
&self.router_socket_addr
))
.get(format!("http://{}/health?ready", &self.router_socket_addr))
.header("Content-Type", "application/json")
.send()
.and_then(|r| r.error_for_status())
Expand Down Expand Up @@ -254,3 +250,61 @@ impl Drop for RouterRunner {
let _ = self.kill().map_err(log_err_and_continue);
}
}

#[cfg(test)]
mod tests {
use httpmock::MockServer;
use rstest::*;
use speculoos::prelude::*;

use crate::{
options::{LicenseAccepter, ProfileOpt},
utils::client::ClientBuilder,
};

use super::*;

#[rstest]
fn test_wait_for_startup() {
// GIVEN
// * a mock health endpoint that returns 200
// * a RouterRunner
let server = MockServer::start();
let health_mock = server.mock(|when, then| {
when.method("GET").path("/health").query_param("ready", "");
then.status(200);
});

let mut router_runner = RouterRunner::new(
Default::default(),
Default::default(),
PluginOpts {
profile: ProfileOpt {
profile_name: Default::default(),
},
elv2_license_accepter: LicenseAccepter {
elv2_license_accepted: Some(true),
},
skip_update: true,
},
server.address().clone(),
"".to_string(),
None,
StudioClientConfig::new(
None,
houston::Config::new(None::<&Utf8PathBuf>, None).unwrap(),
false,
ClientBuilder::new(),
),
);

// WHEN waiting for router startup
let res = router_runner.wait_for_startup(Client::new());

// THEN
// * it succeeds
// * it calls the mock endpoint correctly
assert_that!(res).is_ok();
health_mock.assert();
}
}

0 comments on commit 74eb9d7

Please sign in to comment.