Added compose-wait-healthy.
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
name: compose-wait-healthy
|
||||
description: "Wait until every named docker-compose service reports 'healthy' (or 'running' when no HEALTHCHECK is defined). On timeout, dumps tail logs for diagnosis."
|
||||
inputs:
|
||||
services:
|
||||
description: "Whitespace-separated list of compose service names to wait on."
|
||||
required: true
|
||||
deadline:
|
||||
description: "Per-invocation deadline in seconds before the action fails."
|
||||
required: false
|
||||
default: "600"
|
||||
poll:
|
||||
description: "Seconds between polls."
|
||||
required: false
|
||||
default: "5"
|
||||
project:
|
||||
description: "Compose project name (passed as -p). Optional."
|
||||
required: false
|
||||
default: ""
|
||||
workingDirectory:
|
||||
description: "Directory containing the compose.yml/compose.yaml. Defaults to repo root."
|
||||
required: false
|
||||
default: "."
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: "Wait for healthy"
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.workingDirectory }}
|
||||
env:
|
||||
WAIT_HEALTHY_SERVICES: ${{ inputs.services }}
|
||||
WAIT_HEALTHY_DEADLINE: ${{ inputs.deadline }}
|
||||
WAIT_HEALTHY_POLL: ${{ inputs.poll }}
|
||||
COMPOSE_PROJECT: ${{ inputs.project }}
|
||||
run: bash "$GITHUB_ACTION_PATH/wait-healthy.sh"
|
||||
@@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env bash
|
||||
# wait-healthy.sh — poll docker compose services until all are healthy/running.
|
||||
# Invoked by the compose-wait-healthy composite action. Configure via env vars:
|
||||
# WAIT_HEALTHY_SERVICES whitespace-separated list of service names (required)
|
||||
# WAIT_HEALTHY_DEADLINE seconds before the script fails (default: 600)
|
||||
# WAIT_HEALTHY_POLL seconds between polls (default: 5)
|
||||
# COMPOSE_PROJECT compose project name passed via -p (optional)
|
||||
set -euo pipefail
|
||||
|
||||
compose() {
|
||||
if [[ -n "${COMPOSE_PROJECT:-}" ]]; then
|
||||
docker compose -p "${COMPOSE_PROJECT}" "$@"
|
||||
else
|
||||
docker compose "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
read -r -a services <<< "${WAIT_HEALTHY_SERVICES}"
|
||||
if [[ ${#services[@]} -eq 0 ]]; then
|
||||
echo "ERROR: WAIT_HEALTHY_SERVICES is empty" >&2
|
||||
exit 64
|
||||
fi
|
||||
|
||||
deadline="${WAIT_HEALTHY_DEADLINE:-600}"
|
||||
poll="${WAIT_HEALTHY_POLL:-5}"
|
||||
start="$(date +%s)"
|
||||
|
||||
while :; do
|
||||
pending=()
|
||||
for svc in "${services[@]}"; do
|
||||
cid="$(compose ps -q "${svc}" || true)"
|
||||
if [[ -z "${cid}" ]]; then
|
||||
pending+=("${svc}(no container)")
|
||||
continue
|
||||
fi
|
||||
status="$(docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' "${cid}" 2>/dev/null || echo unknown)"
|
||||
case "${status}" in
|
||||
healthy|running) ;;
|
||||
*) pending+=("${svc}=${status}") ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ ${#pending[@]} -eq 0 ]]; then
|
||||
echo "all services healthy: ${services[*]}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
elapsed=$(( $(date +%s) - start ))
|
||||
if (( elapsed > deadline )); then
|
||||
echo "FAIL: timeout after ${elapsed}s waiting on: ${pending[*]}" >&2
|
||||
for svc in "${services[@]}"; do
|
||||
echo "----- ${svc} (last 50 log lines) -----" >&2
|
||||
compose logs --no-color --tail=50 "${svc}" >&2 || true
|
||||
done
|
||||
exit 1
|
||||
fi
|
||||
|
||||
printf '[%4ds] waiting on: %s\n' "${elapsed}" "${pending[*]}"
|
||||
sleep "${poll}"
|
||||
done
|
||||
Reference in New Issue
Block a user