ci: add a throwaway probe of the runner cache server (#234)
Some checks failed
PR Check — Frontend / frontend (pull_request) Successful in 1m41s
Diag — cache server reachability (#234) / probe (pull_request) Failing after 12s

Diagnostic only, never to be merged. Since #232 no workflow calls the
Actions cache, so nothing has shown whether a job container can reach the
cache server today. This job prints the cache address the runner
advertises (path redacted, since job logs are public), probes it over TCP
next to other ports and host addresses, and round-trips a tiny payload
through actions/cache. It is green only if the payload comes back.

Refs #234

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
le king fu 2026-10-03 13:49:36 -04:00
parent 0e4fef5ad7
commit 1326ba1bcc

View file

@ -0,0 +1,144 @@
name: Diag — cache server reachability (#234)
# THROWAWAY DIAGNOSTIC — never merge. Lives on its own branch for #234.
#
# Since #232 no workflow calls the Actions cache: in July both the restore
# (getCacheEntry) and the save (reserveCache) ended in "Request timeout". The
# suspected cause is that the job container cannot reach the cache address the
# runner hands it. This job checks that from inside a job container, without
# host access:
# 1. which cache address the runner advertises (path redacted: it may carry a
# per-run token, and this repository's job logs are public);
# 2. raw TCP reachability of that address, next to other ports and other host
# addresses, to tell "dropped" from "refused" from "open";
# 3. an end-to-end round trip through actions/cache with a tiny payload.
# The job is green only if the payload comes back from the cache server.
#
# Steps that use bash features set `shell: bash`: inside a container the runner
# defaults to `sh`, and a job-level `defaults` block is refused by the runner.
on:
pull_request:
paths:
- '.forgejo/workflows/diag-cache-probe.yml'
permissions:
contents: read
jobs:
probe:
runs-on: ubuntu
container: ubuntu:22.04
timeout-minutes: 20
steps:
- name: Cache address and TCP reachability
shell: bash
run: |
echo "Runner-provided variables (names only):"
compgen -e | grep -E 'ACTIONS|RUNNER|FORGEJO|GITEA' | sort | sed 's/^/ /'
compgen -e | grep -E '_RUNNER_VERSION$' | while read -r v; do echo " $v=${!v}"; done
url="${ACTIONS_CACHE_URL:-}"
if [ -z "$url" ]; then
echo "ACTIONS_CACHE_URL is empty: the runner gives this job no cache server."
exit 0
fi
base=$(printf '%s' "$url" | sed -E 's#^(https?://[^/]+).*#\1#')
scheme=${base%%://*}
hostport=${base#*://}
case "$hostport" in
\[*\]:*) host=${hostport%]:*}; host=${host#[}; port=${hostport##*]:} ;;
*:*) host=${hostport%:*}; port=${hostport##*:} ;;
*) host=$hostport; port="" ;;
esac
if [ -z "$port" ]; then
if [ "$scheme" = https ]; then port=443; else port=80; fi
fi
shown=$host
case "$host" in *:*) shown="[$host]" ;; esac
echo
echo "Cache address advertised by the runner: $scheme://$shown:$port/<path redacted>"
forge=$(getent ahostsv4 git.lacompagniemaximus.com | awk '{ print $1; exit }')
echo "git.lacompagniemaximus.com resolves to (IPv4): ${forge:-unresolved}"
echo "Container addresses: $(hostname -I 2>/dev/null || echo unknown)"
gw_hex=$(awk '$2 == "00000000" { print $3; exit }' /proc/net/route)
gw=""
if [ -n "$gw_hex" ]; then
gw=$(printf '%d.%d.%d.%d' "0x${gw_hex:6:2}" "0x${gw_hex:4:2}" "0x${gw_hex:2:2}" "0x${gw_hex:0:2}")
fi
echo "Default gateway (the host, seen from this job network): ${gw:-unknown}"
probe() {
local label=$1 h=$2 p=$3 start ms rc err verdict
start=$(date +%s%N)
err=$(timeout 10 bash -c "exec 3<>/dev/tcp/$h/$p" 2>&1)
rc=$?
ms=$(( ($(date +%s%N) - start) / 1000000 ))
case $rc in
0) verdict="OPEN" ;;
124) verdict="TIMEOUT" ;;
*) case "$err" in
*refused*) verdict="REFUSED" ;;
*) verdict="ERROR (${err##*: })" ;;
esac ;;
esac
printf ' %-36s %-26s %-8s %6d ms\n' "$label" "$h:$p" "$verdict" "$ms"
}
echo
echo "TCP probes, 10 s each. OPEN = handshake done; REFUSED = the host answered"
echo "but nothing listens there; TIMEOUT = no answer (packets dropped, or the"
echo "address is unreachable from this network)."
probe "advertised cache address" "$host" "$port"
probe "same host, port 22 (sshd)" "$host" 22
probe "same host, port 443 (Traefik)" "$host" 443
if [ -n "$gw" ]; then
probe "job network gateway, cache port" "$gw" "$port"
probe "job network gateway, port 22" "$gw" 22
fi
probe "docker0 172.17.0.1, cache port" 172.17.0.1 "$port"
- name: Install Node.js 20
run: |
apt-get update
apt-get install -y --no-install-recommends curl ca-certificates
# actions/cache is a JavaScript action: it needs `node` in the container PATH.
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
apt-get install -y nodejs
node --version
- name: Write a tiny payload
id: payload
shell: bash
run: |
key="diag-234-$(date -u +%Y%m%dT%H%M%SZ)-$RANDOM"
mkdir -p probe-payload
printf '%s' "$key" > probe-payload/stamp
echo "key=$key" >> "$GITHUB_OUTPUT"
echo "payload key: $key"
- name: Save it (actions/cache/save)
uses: https://github.com/actions/cache/save@v4
with:
path: probe-payload
key: ${{ steps.payload.outputs.key }}
- name: Delete the local copy
run: rm -rf probe-payload
- name: Restore it (actions/cache/restore, fails on a miss)
uses: https://github.com/actions/cache/restore@v4
with:
path: probe-payload
key: ${{ steps.payload.outputs.key }}
fail-on-cache-miss: true
- name: Check the payload made the round trip
shell: bash
run: |
if [ "$(cat probe-payload/stamp 2>/dev/null)" = "${{ steps.payload.outputs.key }}" ]; then
echo "ROUND TRIP OK: the payload came back from the cache server."
else
echo "ROUND TRIP FAILED: the payload is missing or different."
exit 1
fi