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