Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .earthly/config.selfhosted.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ global:
tls_enabled: false
disable_analytics: true
buildkit_max_parallelism: 16
cache_size_pct: 50
cache_size_pct: 20
22 changes: 13 additions & 9 deletions .github/actions/local-environment-tests/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,14 +98,18 @@ runs:
WALLET_INDEXER_IMAGE: ${{ inputs.wallet-indexer-image }}
DOCKERHUB_USER: ${{ inputs.dockerhub-username }}
DOCKERHUB_TOKEN: ${{ inputs.dockerhub-password }}
# Wrapped in retry-transient-ci.sh: retries only on a known-transient CI
# failure (buildkit recycled by a concurrent job, or a dropped ghcr push);
# genuine failures fail fast. See that script.
run: |
. ./.envrc
earthly -P \
--secret DOCKERHUB_USER="$DOCKERHUB_USER" \
--secret DOCKERHUB_TOKEN="$DOCKERHUB_TOKEN" \
+local-env-ci \
--NODE_IMAGE="$NODE_IMAGE" \
--TOOLKIT_IMAGE="$TOOLKIT_IMAGE" \
--INDEXER_API_IMAGE="$INDEXER_API_IMAGE" \
--CHAIN_INDEXER_IMAGE="$CHAIN_INDEXER_IMAGE" \
--WALLET_INDEXER_IMAGE="$WALLET_INDEXER_IMAGE"
./.github/scripts/retry-transient-ci.sh \
earthly -P \
--secret DOCKERHUB_USER="$DOCKERHUB_USER" \
--secret DOCKERHUB_TOKEN="$DOCKERHUB_TOKEN" \
+local-env-ci \
--NODE_IMAGE="$NODE_IMAGE" \
--TOOLKIT_IMAGE="$TOOLKIT_IMAGE" \
--INDEXER_API_IMAGE="$INDEXER_API_IMAGE" \
--CHAIN_INDEXER_IMAGE="$CHAIN_INDEXER_IMAGE" \
--WALLET_INDEXER_IMAGE="$WALLET_INDEXER_IMAGE"
28 changes: 16 additions & 12 deletions .github/actions/reusable-e2e-tests/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,25 @@ runs:
password: ${{ inputs.ghcr-password }}

- name: Run JUST command
env:
JUST_COMMAND: ${{ inputs.just-command }}
NODE_IMAGE: ${{ inputs.node-image }}
TOOLKIT_IMAGE: ${{ inputs.toolkit-image }}
shell: bash
run: |
echo "🧪 Running E2E command: ${{ inputs.just-command }}"
echo "🧪 Running E2E command: $JUST_COMMAND"

case "${{ inputs.just-command }}" in
# Resolve the just invocation (which positional images each command wants),
# then run it through retry-transient-ci.sh: retries only on a known-transient
# CI failure (buildkit recycled by a concurrent job, or a dropped ghcr push);
# a genuine E2E failure fails fast.
case "$JUST_COMMAND" in
indexer-api-e2e)
just "${{ inputs.just-command }}"
;;
startup-dev-e2e | startup-qanet-e2e)
just "${{ inputs.just-command }}" "${{ inputs.node-image }}"
;;
args=(just "$JUST_COMMAND") ;;
toolkit-e2e | toolkit-update-ledger-parameters-e2e | toolkit-maintenance-e2e | toolkit-mint-e2e | toolkit-tokens-minter-e2e | toolkit-contracts-e2e | genesis-wallets-undeployed-e2e | genesis-wallets-devnet-e2e)
just "${{ inputs.just-command }}" "${{ inputs.node-image }}" "${{ inputs.toolkit-image }}"
;;
args=(just "$JUST_COMMAND" "$NODE_IMAGE" "$TOOLKIT_IMAGE") ;;
*)
just "${{ inputs.just-command }}" "${{ inputs.node-image }}"
;;
args=(just "$JUST_COMMAND" "$NODE_IMAGE") ;;
esac
shell: bash

./.github/scripts/retry-transient-ci.sh "${args[@]}"
33 changes: 33 additions & 0 deletions .github/scripts/retry-transient-ci.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/env bash
# Run "$@" up to 3 times, retrying ONLY on a known-transient CI failure:
#
# * shared self-hosted buildkitd recycled out from under the build — a
# concurrent job connected with a different earthly settings hash and
# SIGTERMed the daemon, taking down every in-flight build on the host;
# * a dropped ghcr.io layer push ("timeout awaiting response headers" and
# friends) — buildkit's registry response-header timeout isn't tunable.
#
# Earthly's cache makes the retry cheap (work that already succeeded is
# skipped). A genuine build/test failure does NOT match TRANSIENT_RE and fails
# fast on attempt 1, so a real regression is never masked by a blind retry.
#
# Only "$1" (the command name) is echoed — never "$*", which would leak
# --secret values passed as arguments into the CI log.
set -uo pipefail

TRANSIENT_RE='Shutdown signal received|killing buildkit pid|transport is closing|rpc error: code = Unavailable|connection reset by peer|failed to connect to buildkit|timeout awaiting response headers|TLS handshake timeout|i/o timeout'
LOG="${RUNNER_TEMP:-/tmp}/retry-transient-ci.$$.log"

for attempt in 1 2 3; do
echo "----- $1: attempt $attempt/3 -----"
"$@" 2>&1 | tee "$LOG"
rc=${PIPESTATUS[0]}
[ "$rc" -eq 0 ] && exit 0
if [ "$attempt" -lt 3 ] && grep -qE "$TRANSIENT_RE" "$LOG"; then
echo "::warning::$1: transient CI failure (buildkit recycle / registry push) — retrying in 30s (attempt $attempt/3)"
sleep 30
continue
fi
echo "$1 failed (rc=$rc); not a transient signature or attempts exhausted — not retrying"
exit "$rc"
done
31 changes: 8 additions & 23 deletions .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -171,30 +171,15 @@ jobs:
echo "[net]" >> "$HOME"/.cargo/config
echo "git-fetch-with-cli = true" >> "$HOME"/.cargo/config

# Retry the earthly invocation up to 3 times. Buildkit's default
# response-header timeout for registry uploads (~30s in the
# underlying containerd resolver) isn't tunable via buildkitd.toml,
# and the self-hosted -> ghcr.io path occasionally drops a layer push
# with "timeout awaiting response headers". Earthly's cache means
# retries skip everything that already succeeded — they essentially
# only retry the failing push.
#
# No ::group:: wrapping — failures need to be visible by default in
# the GHA log, not collapsed.
# Retry the earthly invocation via the shared retry-transient-ci.sh.
# It absorbs the two transient CI failure classes — buildkitd recycled
# by a concurrent job, and dropped ghcr.io layer pushes ("timeout
# awaiting response headers"; buildkit's registry response-header
# timeout isn't tunable) — while failing fast on a genuine build error
# (earthly's cache means a retry only re-does the failing push anyway).
. ./.envrc
for attempt in 1 2 3; do
echo "----- earthly attempt $attempt/3 -----"
if earthly --secret GITHUB_TOKEN="$GITHUB_TOKEN" -P --push +images; then
exit 0
fi
echo "----- earthly attempt $attempt failed -----"
if [ $attempt -lt 3 ]; then
echo "sleeping 30s before retry"
sleep 30
fi
done
echo "earthly failed after 3 attempts"
exit 1
./.github/scripts/retry-transient-ci.sh \
earthly --secret GITHUB_TOKEN="$GITHUB_TOKEN" -P --push +images

- name: Upload build artifacts
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
Expand Down
Loading