From c96b36a41f4eed7fc2d555e0d6cad3ceb899c230 Mon Sep 17 00:00:00 2001 From: Minseong Choi Date: Sun, 19 Jul 2026 19:21:26 +0900 Subject: [PATCH] fix(bootstrap): retry transient Fill failures when resolving build jars A single HTTP 502 from fill.papermc.io aborted the entire bootstrap. Build resolution used a one-shot curl, so one gateway blip from an upstream that flaps was indistinguishable from a permanent failure, and the run died before Docker, k3s or any game server was provisioned. Pass --retry 5 --retry-delay 2 to the build-resolution fetches. 502/503/504 are already in curl's built-in transient set, so the tool had solved this; the flags were simply never passed. papermc_latest_jar is shared by the Paper and the Velocity resolve, so hardening it once covers both callers. The LOOHP/Limbo CI metadata fetch feeds the same step and gets the same treatment. Deliberately no --retry-connrefused. It only adds ECONNREFUSED to a set that already covers this incident, and it needs curl 7.52.0 while the yum (el7) path the script supports ships 7.29.0, where an unrecognised long option is a parse error rather than a warning: # centos:7, curl 7.29.0 $ curl -fsSL --retry 5 --retry-delay 2 --retry-connrefused https://example.com curl: option --retry-connrefused: is unknown Under set -Eeuo pipefail that exits 2 and trips the || die, so both hardened fetches would hard-fail on a host where they used to work, each naming a cause that is not the real one. A comment above papermc_latest_jar records this so the flag does not come back. The failure message was actively misleading. "no Paper build for Minecraft 26.2 (the login gate speaks only that protocol)" reads as "that Minecraft version is unsupported", sending the reader after a version-pinning problem that does not exist: Paper 26.2 build 60 resolved fine minutes later. Say what is actually known instead, that the build likely exists and Fill is flapping. Verified against a local always-502 server: curl now issues 6 requests (1 initial + 5 retries) over 10.1s before giving up, where it previously issued 1 and died. Verified on centos:7 that this flag set is accepted, and against the live Fill v3 API that the resolve still returns a jar URL. Known and deliberately unchanged: no fetch sets --max-time, so an upstream that accepts a connection and never answers still blocks forever. --retry does not cover that, as it fires only once a request completes with a failure. The remaining single-shot downloads (cloudflared, the Docker GPG key and repo list, k3s, the Temurin JRE, the Velocity jar, the Go toolchain) keep their existing no-retry shape rather than widen this diff on a script that is about to provision a live host. --- deploy/bootstrap.sh | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/deploy/bootstrap.sh b/deploy/bootstrap.sh index e7c59c7..f70bd84 100644 --- a/deploy/bootstrap.sh +++ b/deploy/bootstrap.sh @@ -782,7 +782,8 @@ resolve_game_jars() { log "resolving the newest LOOHP/Limbo CI build" # Fetch first, filter second: `curl | grep | head` dies of SIGPIPE under `set -o pipefail` # the moment head closes the pipe early. Same shape everywhere below. - meta="$(curl -fsSL "${ci}/api/json")" || die "could not read the LOOHP/Limbo CI build metadata" + meta="$(curl -fsSL --retry 5 --retry-delay 2 "${ci}/api/json")" \ + || die "could not read the LOOHP/Limbo CI build metadata" file="$(printf '%s' "$meta" | grep -o 'Limbo-[0-9A-Za-z._-]*\.jar' || true)" file="${file%%$'\n'*}" [ -n "$file" ] || die "no Limbo jar in the LOOHP/Limbo CI artifact list" @@ -799,14 +800,19 @@ resolve_game_jars() { # is never coming back; Fill wants a descriptive User-Agent. log "resolving the newest Paper ${MC_VERSION} build" PAPER_JAR_URL="$(papermc_latest_jar paper "$MC_VERSION")" \ - || die "no Paper build for Minecraft ${MC_VERSION} (the login gate speaks only that protocol)" + || die "could not resolve a Paper build for Minecraft ${MC_VERSION} (the login gate pins this protocol; the build likely exists — Fill upstream is down or flapping)" ok "Limbo ${LIMBO_VERSION} + Paper, both on Minecraft ${MC_VERSION}" } # papermc_latest_jar prints the download URL of the newest build of . +# --retry rides out Fill's transient gateway errors (502/503/504 are in curl's retry +# set): a single blip must not abort the whole bootstrap claiming the build is missing. +# Plain --retry only, deliberately: --retry-connrefused needs curl 7.52+, which the yum +# (el7) path does not have, and it would only add ECONNREFUSED to an already-covered set. papermc_latest_jar() { local project="$1" version="$2" json urls url - json="$(curl -fsSL -A "felis-bootstrap (+https://github.com/MliroLirrorsIngenuity/Felis)" \ + json="$(curl -fsSL --retry 5 --retry-delay 2 \ + -A "felis-bootstrap (+https://github.com/MliroLirrorsIngenuity/Felis)" \ "https://fill.papermc.io/v3/projects/${project}/versions/${version}/builds/latest")" || return 1 urls="$(printf '%s' "$json" | grep -o 'https://fill-data\.papermc\.io/[^"]*\.jar' || true)" url="${urls%%$'\n'*}"