Skip to content

Commit e756367

Browse files
committed
fix connections get errors
1 parent 0e3f55c commit e756367

3 files changed

Lines changed: 86 additions & 17 deletions

File tree

src/api.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,24 @@ impl ApiClient {
171171
}
172172
}
173173

174+
/// GET request, exits only on connection error, returns raw (status, body).
175+
/// Use for best-effort endpoints (e.g. health checks) where the caller wants
176+
/// to handle non-2xx responses gracefully instead of aborting.
177+
pub fn get_raw(&self, path: &str) -> (reqwest::StatusCode, String) {
178+
let url = format!("{}{path}", self.api_url);
179+
self.log_request("GET", &url, None);
180+
181+
let resp = match self.build_request(reqwest::Method::GET, &url).send() {
182+
Ok(r) => r,
183+
Err(e) => {
184+
eprintln!("error connecting to API: {e}");
185+
std::process::exit(1);
186+
}
187+
};
188+
189+
util::debug_response(resp)
190+
}
191+
174192
/// POST request with JSON body, exits on error, returns raw (status, body).
175193
pub fn post_raw(&self, path: &str, body: &serde_json::Value) -> (reqwest::StatusCode, String) {
176194
let url = format!("{}{path}", self.api_url);

src/connections.rs

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,56 @@ struct HealthResponse {
1212
error: Option<String>,
1313
}
1414

15-
fn fetch_health(api: &ApiClient, connection_id: &str, show_spinner: bool) -> HealthResponse {
15+
/// Result of a best-effort health check. Either the endpoint responded with a
16+
/// parseable body, or it did not — in which case we record why and keep going.
17+
enum HealthStatus {
18+
Available(HealthResponse),
19+
Unavailable(String),
20+
}
21+
22+
impl HealthStatus {
23+
fn is_confirmed_unhealthy(&self) -> bool {
24+
matches!(self, HealthStatus::Available(h) if !h.healthy)
25+
}
26+
}
27+
28+
impl Serialize for HealthStatus {
29+
fn serialize<S: serde::Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
30+
match self {
31+
HealthStatus::Available(h) => h.serialize(ser),
32+
HealthStatus::Unavailable(_) => ser.serialize_none(),
33+
}
34+
}
35+
}
36+
37+
fn fetch_health(api: &ApiClient, connection_id: &str, show_spinner: bool) -> HealthStatus {
1638
let spinner = show_spinner.then(|| crate::util::spinner("Checking connection health..."));
17-
let health: HealthResponse = api.get(&format!("/connections/{connection_id}/health"));
39+
let (status, body) = api.get_raw(&format!("/connections/{connection_id}/health"));
1840
if let Some(s) = spinner { s.finish_and_clear(); }
19-
health
41+
42+
if !status.is_success() {
43+
return HealthStatus::Unavailable(crate::util::api_error(body));
44+
}
45+
match serde_json::from_str::<HealthResponse>(&body) {
46+
Ok(h) => HealthStatus::Available(h),
47+
Err(e) => HealthStatus::Unavailable(format!("parse error: {e}")),
48+
}
2049
}
2150

22-
fn format_health(health: &HealthResponse) -> String {
51+
fn format_health(health: &HealthStatus) -> String {
2352
use crossterm::style::Stylize;
24-
if health.healthy {
25-
match health.latency_ms {
53+
match health {
54+
HealthStatus::Available(h) if h.healthy => match h.latency_ms {
2655
Some(ms) => format!("{} {}", "healthy".green(), format!("({ms}ms)").dark_grey()),
2756
None => "healthy".green().to_string(),
57+
},
58+
HealthStatus::Available(h) => {
59+
let err = h.error.as_deref().unwrap_or("unknown error");
60+
format!("{} — {}", "unhealthy".red(), err)
61+
}
62+
HealthStatus::Unavailable(err) => {
63+
format!("{} — {}", "unavailable".yellow(), err)
2864
}
29-
} else {
30-
let err = health.error.as_deref().unwrap_or("unknown error");
31-
format!("{} — {}", "unhealthy".red(), err)
3265
}
3366
}
3467

@@ -260,7 +293,7 @@ pub fn create(
260293
_ => unreachable!(),
261294
}
262295

263-
if !health.healthy {
296+
if health.is_confirmed_unhealthy() {
264297
std::process::exit(1);
265298
}
266299
}

src/connections_new.rs

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,11 @@ pub fn run(workspace_id: &str) {
277277
error: Option<String>,
278278
}
279279

280+
enum HealthStatus {
281+
Available(HealthResponse),
282+
Unavailable(String),
283+
}
284+
280285
let create_spinner = crate::util::spinner("Creating connection...");
281286
let (status_code, resp_body) = api.post_raw("/connections", &body);
282287
create_spinner.finish_and_clear();
@@ -296,9 +301,18 @@ pub fn run(workspace_id: &str) {
296301
};
297302

298303
let health_spinner = crate::util::spinner("Checking connection health...");
299-
let health: HealthResponse = api.get(&format!("/connections/{}/health", result.id));
304+
let (hstatus, hbody) = api.get_raw(&format!("/connections/{}/health", result.id));
300305
health_spinner.finish_and_clear();
301306

307+
let health = if !hstatus.is_success() {
308+
HealthStatus::Unavailable(crate::util::api_error(hbody))
309+
} else {
310+
match serde_json::from_str::<HealthResponse>(&hbody) {
311+
Ok(h) => HealthStatus::Available(h),
312+
Err(e) => HealthStatus::Unavailable(format!("parse error: {e}")),
313+
}
314+
};
315+
302316
println!("{}", "Connection created".green());
303317
println!("id: {}", result.id);
304318
println!("name: {}", result.name);
@@ -310,18 +324,22 @@ pub fn run(workspace_id: &str) {
310324
_ => result.discovery_status.yellow().to_string(),
311325
};
312326
println!("discovery_status: {status}");
313-
let health_str = if health.healthy {
314-
match health.latency_ms {
327+
let health_str = match &health {
328+
HealthStatus::Available(h) if h.healthy => match h.latency_ms {
315329
Some(ms) => format!("{} {}", "healthy".green(), format!("({ms}ms)").dark_grey()),
316330
None => "healthy".green().to_string(),
331+
},
332+
HealthStatus::Available(h) => {
333+
let err = h.error.as_deref().unwrap_or("unknown error");
334+
format!("{} — {}", "unhealthy".red(), err)
335+
}
336+
HealthStatus::Unavailable(err) => {
337+
format!("{} — {}", "unavailable".yellow(), err)
317338
}
318-
} else {
319-
let err = health.error.as_deref().unwrap_or("unknown error");
320-
format!("{} — {}", "unhealthy".red(), err)
321339
};
322340
println!("health: {health_str}");
323341

324-
if !health.healthy {
342+
if matches!(&health, HealthStatus::Available(h) if !h.healthy) {
325343
std::process::exit(1);
326344
}
327345
}

0 commit comments

Comments
 (0)