Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 53 additions & 6 deletions crates/cli/src/bootstrap/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ impl GatewaySpec {
log::error!(
target: "nemo_relay.bootstrap",
event = "gateway_acquisition_failed",
bind = self.bind.to_string().as_str();
bind = self.bind.to_string().as_str(),
failure_kind = bootstrap_failure_kind(&error);
"Gateway acquisition failed"
);
Err(error)
Expand Down Expand Up @@ -120,7 +121,8 @@ impl GatewaySpec {
log::error!(
target: "nemo_relay.bootstrap",
event = "gateway_recovery_failed",
instance_id = expected_instance;
instance_id = expected_instance,
failure_kind = bootstrap_failure_kind(&error);
"Gateway recovery failed"
);
Err(error)
Expand Down Expand Up @@ -200,8 +202,17 @@ fn acquire_gateway(spec: &GatewaySpec) -> Result<GatewayEndpoint, String> {
Err(incompatible_relay_error(&url))
}
}
(RelayHealth::Foreign, _) => Err(foreign_listener_error(&url)),
(RelayHealth::Unavailable, _) => start_gateway(spec, &state),
(RelayHealth::Foreign, _) => {
if state::stop_unhealthy_owned_gateway_locked(&state, &url)? {
start_gateway(spec, &state)
} else {
Err(foreign_listener_error(&url))
}
}
(RelayHealth::Unavailable, _) => {
state::stop_unhealthy_owned_gateway_locked(&state, &url)?;
start_gateway(spec, &state)
}
}
}

Expand All @@ -220,8 +231,14 @@ fn recover_gateway(spec: &GatewaySpec, expected_instance: &str) -> Result<Gatewa
return compatible_endpoint(spec.bind, requested_url, instance_id);
}
(RelayHealth::Incompatible, _) => return Err(incompatible_relay_error(&requested_url)),
(RelayHealth::Foreign, _) => return Err(foreign_listener_error(&requested_url)),
(RelayHealth::Unavailable, _) => {}
(RelayHealth::Foreign, _) => {
if !state::stop_unhealthy_owned_gateway_locked(&state, &requested_url)? {
return Err(foreign_listener_error(&requested_url));
}
}
(RelayHealth::Unavailable, _) => {
state::stop_unhealthy_owned_gateway_locked(&state, &requested_url)?;
}
}
}

Expand Down Expand Up @@ -285,17 +302,47 @@ fn compatible_endpoint(
}

fn foreign_listener_error(url: &str) -> String {
log::error!(
target: "nemo_relay.bootstrap",
event = "gateway_port_conflict",
endpoint = url,
observed_health = "unverified_listener",
remediation = "stop_listener_or_configure_another_port";
"Gateway endpoint is occupied by an unverified listener"
);
format!(
"{url} is occupied by a service that is not a compatible NeMo Relay gateway; stop that service or configure another port"
)
}

fn incompatible_relay_error(url: &str) -> String {
log::error!(
target: "nemo_relay.bootstrap",
event = "gateway_port_conflict",
endpoint = url,
observed_health = "incompatible_relay",
remediation = "stop_gateway_wait_for_idle_shutdown_or_reinstall_with_force";
"Gateway endpoint is occupied by an incompatible NeMo Relay gateway"
);
format!(
"{url} is occupied by NeMo Relay with a different version or persistent configuration; stop it, wait for idle shutdown, or reinstall the integration with --force"
)
}

fn bootstrap_failure_kind(error: &str) -> &'static str {
if error.contains("not a compatible NeMo Relay gateway") {
"foreign_listener"
} else if error.contains("different version or persistent configuration") {
"incompatible_gateway"
} else if error.contains("became unhealthy") {
"unhealthy_gateway"
} else if error.contains("did not become ready") {
"gateway_readiness_timeout"
} else {
"bootstrap_failure"
}
}

fn start_gateway(spec: &GatewaySpec, state: &Path) -> Result<GatewayEndpoint, String> {
log::info!(
target: "nemo_relay.bootstrap",
Expand Down
Loading
Loading