fix(forge): set mirror_interval so pull-mirrors sync periodically, not on-access
Forgejo's default mirror behaviour syncs on every git access, which re-introduces external DNS latency at clone time. The hive-ci runner shares the host netns, so a host-resolver blip turns an otherwise local clone into a hard failure (data.forgejo.org DNS lookup that has nothing to do with the repo being cloned). Fix: - New MIRROR_INTERVAL const (8h0m0s) used in ensure_mirror_repo. - On creation: pass interval=MIRROR_INTERVAL in the migrate API body. - On existing mirror: PATCH mirror_interval on every startup so repos seeded before this change converge without manual intervention. A stale mirror (up to 8 hours old) is fine for CI; a broken clone from a transient DNS blip is not. The actions/checkout mirror is refreshed periodically rather than triggered by runner pulls.
This commit is contained in:
parent
7def514760
commit
9496fb060b
1 changed files with 31 additions and 7 deletions
|
|
@ -977,20 +977,41 @@ async fn ensure_mirrors(admin_token: &str) {
|
|||
}
|
||||
}
|
||||
|
||||
/// Periodic sync interval for pull-mirrors. Forgejo syncs mirrors
|
||||
/// on-access by default, which re-introduces external DNS latency on
|
||||
/// every `git clone` (the hive-ci runner shares the host netns and is
|
||||
/// therefore affected by host resolver blips). A fixed periodic interval
|
||||
/// isolates CI from transient DNS failures — a stale mirror is
|
||||
/// acceptable; a broken clone because of a momentary DNS blip is not.
|
||||
const MIRROR_INTERVAL: &str = "8h0m0s";
|
||||
|
||||
/// Create `owner/repo` as a pull-mirror of `upstream` via the migrate API.
|
||||
/// Idempotent: a cheap existence check skips an already-seeded mirror (it
|
||||
/// persists in the non-ephemeral forge state across reboots); a 409 (a race
|
||||
/// between that check and the POST) is also treated as success.
|
||||
/// Idempotent: if the repo already exists this function patches its
|
||||
/// `mirror_interval` to ensure it matches (covers mirrors that were
|
||||
/// created before the interval was introduced). A 409 on the migrate
|
||||
/// POST (a race between the GET check and the POST) is also success.
|
||||
async fn ensure_mirror_repo(
|
||||
upstream: &str,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
admin_token: &str,
|
||||
) -> Result<()> {
|
||||
let get_url = format!("{FORGE_HTTP}/api/v1/repos/{owner}/{repo}");
|
||||
let (status, _) = forge_http(reqwest::Method::GET, &get_url, admin_token, "").await?;
|
||||
let repo_url = format!("{FORGE_HTTP}/api/v1/repos/{owner}/{repo}");
|
||||
let (status, _) = forge_http(reqwest::Method::GET, &repo_url, admin_token, "").await?;
|
||||
if status.is_success() {
|
||||
tracing::debug!(%owner, %repo, "forge: pull-mirror already present");
|
||||
// Mirror already present. Patch interval so mirrors seeded before
|
||||
// this field was introduced (or with a different value) converge.
|
||||
let patch_body = serde_json::json!({ "mirror_interval": MIRROR_INTERVAL }).to_string();
|
||||
let (patch_status, patch_text) =
|
||||
forge_http(reqwest::Method::PATCH, &repo_url, admin_token, &patch_body).await?;
|
||||
if patch_status.is_success() {
|
||||
tracing::debug!(%owner, %repo, interval = MIRROR_INTERVAL, "forge: pull-mirror interval updated");
|
||||
} else {
|
||||
tracing::warn!(
|
||||
%owner, %repo, status = %patch_status, body = %patch_text,
|
||||
"forge: failed to set mirror_interval on existing pull-mirror"
|
||||
);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
// serde_json::json! → the upstream URL is escaped safely (no string
|
||||
|
|
@ -1000,6 +1021,9 @@ async fn ensure_mirror_repo(
|
|||
"repo_owner": owner,
|
||||
"repo_name": repo,
|
||||
"mirror": true,
|
||||
// Periodic refresh instead of on-access sync — keeps CI isolated
|
||||
// from external DNS failures at clone time.
|
||||
"interval": MIRROR_INTERVAL,
|
||||
"service": "git",
|
||||
"private": false,
|
||||
})
|
||||
|
|
@ -1008,7 +1032,7 @@ async fn ensure_mirror_repo(
|
|||
let (status, text) = forge_http(reqwest::Method::POST, &url, admin_token, &body).await?;
|
||||
match status.as_u16() {
|
||||
201 => {
|
||||
tracing::info!(%owner, %repo, %upstream, "forge: created pull-mirror");
|
||||
tracing::info!(%owner, %repo, %upstream, interval = MIRROR_INTERVAL, "forge: created pull-mirror");
|
||||
Ok(())
|
||||
}
|
||||
// 409 = a race created it between our GET check and here (the GET
|
||||
|
|
|
|||
Loading…
Reference in a new issue