From e3cbbb2e0d6a9b2b7eacdb7ffd6db8218711cfc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Falc=C3=B3n?= Date: Thu, 4 Jun 2026 08:46:18 +0200 Subject: [PATCH] ci: make deploy webhook curl robust and observable (#484) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Problem The deploy step intermittently fails on CI with only: ``` Response: HTTP Status: 000 Deployment request failed with status 000 ``` `000` means curl never completed a connection — the Coolify box (which rebuilds the image from git on deploy) has its API unreachable while a prior build runs. But the step gave no way to confirm that: `-s` silenced curl's error message and `|| true` swallowed the exit code. ## Changes - **Surface the real cause** — `-sS` plus `--write-out %{exitcode}`/`%{errormsg}`/timing, so failures print the curl exit code (7 refused, 28 timeout, …) and message instead of a blind `000`. - **Robust parsing** — body/metadata split on an explicit `===CURL_META===` marker instead of fragile `tail`/`sed` line counting. - **No false timeouts** — `--max-time` raised 120→300s so a slow-but-alive box doesn't abort mid-trigger and report a phantom `000`. - **Wider retry window** — 10 attempts with backoff capped at 60s (~8 min) instead of 5 with a 240s dead sleep, to ride out a multi-minute rebuild. - **Fail fast on 4xx** — a bad token/uuid is not retryable, so don't waste the window on it. ## Note This makes the trigger robust and observable; the structural fix (let Coolify pull the prebuilt ghcr image instead of rebuilding on the box) is out of scope here. --- .github/workflows/ci.yml | 47 ++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 26eb1030..1afa5eb9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -588,33 +588,58 @@ jobs: - name: Trigger deployment if: steps.deploy_guard.outputs.should_deploy == 'true' run: | - max_attempts=5 + # The Coolify box rebuilds the image from git on deploy, so its API + # (port 8000) can be unreachable for several minutes while a prior + # build runs. We just need the webhook to land once: retry on + # connection-level failures with a capped backoff over a wide window. + max_attempts=10 + max_delay=60 attempt=1 + # Separator we control, so curl's --write-out fields can never be + # confused with the response body. + marker="===CURL_META===" + while [ $attempt -le $max_attempts ]; do echo "Attempt $attempt of $max_attempts..." - response=$(curl -s -w "\n%{http_code}" \ + curl_exit=0 + response=$(curl -sS \ + -w "${marker}\nhttp_code=%{http_code}\ncurl_exit=%{exitcode}\nerrormsg=%{errormsg}\ntiming=DNS:%{time_namelookup}s Connect:%{time_connect}s Total:%{time_total}s Remote:%{remote_ip}:%{remote_port}" \ --connect-timeout 30 \ - --max-time 120 \ + --max-time 300 \ -H "Authorization: Bearer ${{ secrets.DEPLOYMENT_TOKEN }}" \ - "http://147.93.126.54:8000/api/v1/deploy?uuid=ww00sswosco8w80k08c0occ8&force=false") || true + "http://147.93.126.54:8000/api/v1/deploy?uuid=ww00sswosco8w80k08c0occ8&force=false") || curl_exit=$? - http_code=$(echo "$response" | tail -n1) - body=$(echo "$response" | sed '$d') + body="${response%%${marker}*}" + meta="${response#*${marker}}" + http_code=$(echo "$meta" | sed -n 's/^http_code=//p') + curl_code=$(echo "$meta" | sed -n 's/^curl_exit=//p') + errormsg=$(echo "$meta" | sed -n 's/^errormsg=//p') + timing=$(echo "$meta" | sed -n 's/^timing=//p') - echo "Response: $body" - echo "HTTP Status: ${http_code:-timeout}" + echo "Response body: $body" + echo "HTTP Status: ${http_code:-none}" + echo "curl exit: ${curl_code:-$curl_exit}" + echo "curl error: ${errormsg:-none}" + echo "Timing: $timing" - if [ -n "$http_code" ] && [ "$http_code" -ge 200 ] && [ "$http_code" -lt 300 ]; then + if [ "${http_code:-0}" -ge 200 ] && [ "${http_code:-0}" -lt 300 ]; then echo "Deployment triggered successfully!" exit 0 fi - echo "Deployment request failed with status $http_code" + # 4xx are caller errors (bad token / uuid) — retrying won't help. + if [ "${http_code:-0}" -ge 400 ] && [ "${http_code:-0}" -lt 500 ]; then + echo "Got client error $http_code — not retryable. Failing fast." + exit 1 + fi + + echo "Deployment request failed (http=${http_code:-none} curl_exit=${curl_code:-$curl_exit}: ${errormsg:-none})" if [ $attempt -lt $max_attempts ]; then - delay=$((30 * (2 ** (attempt - 1)))) + delay=$((15 * attempt)) + [ $delay -gt $max_delay ] && delay=$max_delay echo "Retrying in ${delay}s..." sleep $delay fi