fix(swarm-controller): bound the token request, and stop claiming a connection

Both from argus's review on the PR, both non-blocking, both real.

The HTTP client had no timeout, and it runs INSIDE the auth callback: a
token endpoint that accepts the connection and then never answers would
hang the callback and the connection attempt that invoked it, with no
retry and nothing in the log to say why. That is the same hang class the
status endpoint's connection-state check exists to prevent, one layer up.
Failing fast lets async-nats back off and try again, which it already
does well.

And the startup log said "connected to the swarm queue" at a point where
`retry_on_initial_connect` guarantees no connection has been established
yet - so the journal would read "connected", then 503 "not connected"
moments later, and a reader would rightly distrust the second line rather
than the first.
This commit is contained in:
atlas 2026-08-15 18:46:35 +02:00
commit 465d68d5a7
2 changed files with 18 additions and 2 deletions

View file

@ -306,7 +306,14 @@ async fn main() -> Result<()> {
}
Some(cfg) => match queue::connect(cfg).await {
Ok(client) => {
tracing::info!("connected to the swarm queue");
// NOT "connected": `retry_on_initial_connect` returns a client
// before any connection has been established, so claiming a
// connection here would put "connected to the swarm queue" in
// the journal moments before every request 503s with "not
// connected" — and a reader would rightly distrust the second
// line rather than the first. The connection's real state is
// reported by the status endpoint, which checks it per request.
tracing::info!("swarm queue configured; connecting in the background");
Some(Arc::new(status::StatusReader::new(
client,
status::StatusReader::stale_after_from_env(),

View file

@ -135,7 +135,16 @@ async fn mint_token(http: &reqwest::Client, cfg: &QueueConfig) -> Result<String>
/// Connect to the swarm queue, minting a token for each connection attempt.
pub async fn connect(cfg: QueueConfig) -> Result<async_nats::Client> {
let http = reqwest::Client::new();
// A timeout, because this client runs INSIDE the auth callback: a token
// endpoint that accepts the connection and then never answers would hang
// the callback, and with it the connection attempt that invoked it, with
// no retry and nothing in the log to say why. Failing fast lets
// `async-nats` do what it already does well — back off and try again.
// 10s is generous for a form POST to a local IdP.
let http = reqwest::Client::builder()
.timeout(std::time::Duration::from_secs(10))
.build()
.context("building the token-endpoint HTTP client")?;
let url = cfg.url.clone();
let client = async_nats::ConnectOptions::with_auth_callback(move |_nonce| {