fix(#1309): retry forge token read at startup instead of giving up immediately
This commit is contained in:
parent
cf6479b3a9
commit
84e468dadb
1 changed files with 32 additions and 10 deletions
|
|
@ -20,6 +20,13 @@ const POLL_INTERVAL_SECS: u64 = 30;
|
||||||
const HTTP_TIMEOUT_SECS: u64 = 10;
|
const HTTP_TIMEOUT_SECS: u64 = 10;
|
||||||
/// Maximum characters of a body/comment to include in the wake message.
|
/// Maximum characters of a body/comment to include in the wake message.
|
||||||
const BODY_TRUNCATE: usize = 500;
|
const BODY_TRUNCATE: usize = 500;
|
||||||
|
/// How long to wait between token-read retries when the token file is
|
||||||
|
/// missing or unreadable at startup (e.g. hive-priv hasn't provisioned
|
||||||
|
/// it yet, or a chown race left it temporarily root-owned).
|
||||||
|
const TOKEN_RETRY_SECS: u64 = 30;
|
||||||
|
/// Give up waiting for the token after this many retries (~10 minutes).
|
||||||
|
/// Avoids an infinite wait on agents that genuinely have no forge account.
|
||||||
|
const TOKEN_RETRY_MAX: u32 = 20;
|
||||||
|
|
||||||
/// Spawn point: called once from `hive-ag3nt serve` (agent) or
|
/// Spawn point: called once from `hive-ag3nt serve` (agent) or
|
||||||
/// `hive-m1nd serve` (manager). Returns immediately if the forge is not
|
/// `hive-m1nd serve` (manager). Returns immediately if the forge is not
|
||||||
|
|
@ -37,18 +44,33 @@ pub async fn run(socket: PathBuf) {
|
||||||
|
|
||||||
let state_dir = std::env::var("HYPERHIVE_STATE_DIR").unwrap_or_default();
|
let state_dir = std::env::var("HYPERHIVE_STATE_DIR").unwrap_or_default();
|
||||||
let token_path = format!("{state_dir}/forge-token");
|
let token_path = format!("{state_dir}/forge-token");
|
||||||
let token = match tokio::fs::read_to_string(&token_path).await {
|
// Retry reading the token to handle races where hive-priv provisions the
|
||||||
Ok(t) => {
|
// token after the harness starts, or where a parent-container chown briefly
|
||||||
let t = t.trim().to_owned();
|
// makes the file unreadable (see #1304 / #1309). We wait up to
|
||||||
if t.is_empty() {
|
// TOKEN_RETRY_MAX * TOKEN_RETRY_SECS before giving up.
|
||||||
debug!("forge_notify: empty forge token at {token_path} — disabled");
|
let token = {
|
||||||
|
let mut attempts = 0u32;
|
||||||
|
loop {
|
||||||
|
match tokio::fs::read_to_string(&token_path).await {
|
||||||
|
Ok(t) => {
|
||||||
|
let t = t.trim().to_owned();
|
||||||
|
if !t.is_empty() {
|
||||||
|
break t;
|
||||||
|
}
|
||||||
|
debug!("forge_notify: empty forge token at {token_path}");
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
debug!("forge_notify: cannot read token at {token_path}: {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
attempts += 1;
|
||||||
|
if attempts >= TOKEN_RETRY_MAX {
|
||||||
|
debug!(
|
||||||
|
"forge_notify: token not available after {TOKEN_RETRY_MAX} retries — disabled"
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
t
|
tokio::time::sleep(Duration::from_secs(TOKEN_RETRY_SECS)).await;
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
debug!("forge_notify: no forge token at {token_path} ({e}) — disabled");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue