diff --git a/lxc/install.func b/lxc/install.func index de7979f..8e6443d 100644 --- a/lxc/install.func +++ b/lxc/install.func @@ -45,23 +45,34 @@ _cs_core_url() { echo "${COMMUNITY_SCRIPTS_CORE_URL:-https://raw.githubusercontent.com/community-scripts/core/main}/${1:?func path}" } -# Retry options for engine fetches. Repeated here rather than taken from -# core/build.func, which stays on the host while this file is piped into the -# container and has to stand alone. A container is at its most fragile right -# after boot, before DNS is up; core/build.func carries the full reasoning. _CS_CURL_RETRY=(--retry 3 --retry-delay 1 --retry-connrefused --connect-timeout 10) # curl -S prints one line per failed attempt, so a download that recovers on the -# second try would show the user two errors and then quietly work — during a -# spinner, no less. Hold stderr back and release it only if every attempt failed. + _cs_curl_retry() { local url="${1:?url}" err rc=0 + local attempt=1 max_attempts=4 backoff=1 timeout=30 + err="$(mktemp 2>/dev/null)" || { - curl -fsSL "${_CS_CURL_RETRY[@]}" "$url" + curl -fsSL --connect-timeout 10 --max-time "$timeout" "$url" return } - curl -fsSL "${_CS_CURL_RETRY[@]}" "$url" 2>"$err" || rc=$? - ((rc != 0)) && cat "$err" >&2 + + while [[ $attempt -le $max_attempts ]]; do + if curl -fsSL --connect-timeout 10 --max-time "$timeout" "$url" 2>"$err"; then + rm -f "$err" + return 0 + fi + rc=$? + ((attempt == max_attempts)) && break + sleep "$backoff" + backoff=$((backoff * 2)) + ((backoff > 30)) && backoff=30 + timeout=$((timeout * 2)) + ((attempt++)) + done + + cat "$err" >&2 rm -f "$err" return "$rc" }