From 7dc03523d65f16d0d805b3ead85a2bfbec483e27 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 11 Apr 2026 23:28:01 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20bug:=20disinto-edge=20crashes=20on=20col?= =?UTF-8?q?d=20disinto=20up=20=E2=80=94=20clones=20from=20forgejo=20before?= =?UTF-8?q?=20forgejo=20HTTP=20is=20ready=20(#665)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.6 (1M context) --- docker/edge/entrypoint-edge.sh | 22 ++++++++++++++++++++-- lib/generators.sh | 30 ++++++++++++++++++++++-------- 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/docker/edge/entrypoint-edge.sh b/docker/edge/entrypoint-edge.sh index 2a23cf9..d3b08b7 100755 --- a/docker/edge/entrypoint-edge.sh +++ b/docker/edge/entrypoint-edge.sh @@ -80,11 +80,29 @@ fi # Shallow clone at the pinned version — use clean URL, credential helper # supplies auth (#604). +# Retry with exponential backoff — forgejo may still be starting (#665). if [ ! -d /opt/disinto/.git ]; then echo "edge: cloning ${FORGE_URL}/${FORGE_REPO} (branch ${DISINTO_VERSION:-main})..." >&2 - if ! git clone --depth 1 --branch "${DISINTO_VERSION:-main}" "${FORGE_URL}/${FORGE_REPO}.git" /opt/disinto; then + _clone_ok=false + _backoff=2 + _max_backoff=30 + _max_attempts=10 + for _attempt in $(seq 1 "$_max_attempts"); do + if git clone --depth 1 --branch "${DISINTO_VERSION:-main}" "${FORGE_URL}/${FORGE_REPO}.git" /opt/disinto 2>&1; then + _clone_ok=true + break + fi + rm -rf /opt/disinto # clean up partial clone before retry + if [ "$_attempt" -lt "$_max_attempts" ]; then + echo "edge: clone attempt ${_attempt}/${_max_attempts} failed, retrying in ${_backoff}s..." >&2 + sleep "$_backoff" + _backoff=$(( _backoff * 2 )) + if [ "$_backoff" -gt "$_max_backoff" ]; then _backoff=$_max_backoff; fi + fi + done + if [ "$_clone_ok" != "true" ]; then echo >&2 - echo "FATAL: failed to clone ${FORGE_URL}/${FORGE_REPO}.git (branch ${DISINTO_VERSION:-main})" >&2 + echo "FATAL: failed to clone ${FORGE_URL}/${FORGE_REPO}.git (branch ${DISINTO_VERSION:-main}) after ${_max_attempts} attempts" >&2 echo "Likely causes:" >&2 echo " - Forgejo at ${FORGE_URL} is unreachable from the edge container" >&2 echo " - Repository '${FORGE_REPO}' does not exist on this forge" >&2 diff --git a/lib/generators.sh b/lib/generators.sh index 51afa4d..fce3ae1 100644 --- a/lib/generators.sh +++ b/lib/generators.sh @@ -143,8 +143,10 @@ _generate_local_model_services() { ARCHITECT_INTERVAL: "${ARCHITECT_INTERVAL:-21600}" PLANNER_INTERVAL: "${PLANNER_INTERVAL:-43200}" depends_on: - - forgejo - - woodpecker + forgejo: + condition: service_healthy + woodpecker: + condition: service_started networks: - disinto-net profiles: ["agents-${service_name}"] @@ -263,6 +265,12 @@ services: FORGEJO__security__INSTALL_LOCK: "true" FORGEJO__service__DISABLE_REGISTRATION: "true" FORGEJO__webhook__ALLOWED_HOST_LIST: "private" + healthcheck: + test: ["CMD", "wget", "-q", "--spider", "http://localhost:3000/api/v1/version"] + interval: 5s + timeout: 3s + retries: 30 + start_period: 30s networks: - disinto-net @@ -289,7 +297,8 @@ services: WOODPECKER_DATABASE_DATASOURCE: /var/lib/woodpecker/woodpecker.sqlite WOODPECKER_ENVIRONMENT: "FORGE_TOKEN:${FORGE_TOKEN}" depends_on: - - forgejo + forgejo: + condition: service_healthy networks: - disinto-net @@ -364,8 +373,10 @@ services: # .env.vault.enc and are NEVER injected here — only the runner # container receives them at fire time (AD-006, #745). depends_on: - - forgejo - - woodpecker + forgejo: + condition: service_healthy + woodpecker: + condition: service_started networks: - disinto-net @@ -426,9 +437,12 @@ services: - ${CLAUDE_SHARED_DIR:-/var/lib/disinto/claude-shared}:${CLAUDE_SHARED_DIR:-/var/lib/disinto/claude-shared} - ${HOME}/.claude.json:/home/agent/.claude.json:ro depends_on: - - forgejo - - woodpecker - - staging + forgejo: + condition: service_healthy + woodpecker: + condition: service_started + staging: + condition: service_started networks: - disinto-net