Files
awoooi/ops/runner/install-gitea-host-runner-service.sh
Your Name 9b465ee140
All checks were successful
Code Review / ai-code-review (push) Successful in 11s
ci(runner): drain legacy docker act runner safely
2026-05-21 18:53:45 +08:00

157 lines
4.8 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
RUNNER_DIR="${RUNNER_DIR:-/home/wooo/act-runner}"
RUNNER_USER="${RUNNER_USER:-wooo}"
SERVICE_NAME="${SERVICE_NAME:-gitea-act-runner-host.service}"
SHUTDOWN_TIMEOUT="${SHUTDOWN_TIMEOUT:-1h}"
LEGACY_RUNNER_STOP_TIMEOUT_SECONDS="${LEGACY_RUNNER_STOP_TIMEOUT_SECONDS:-3700}"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SYSTEM_SERVICE_SRC="${SCRIPT_DIR}/gitea-act-runner-host.service"
USER_SERVICE_SRC="${SCRIPT_DIR}/gitea-act-runner-host.user.service"
CONFIG_FILE="${RUNNER_DIR}/config.yaml"
gitea_task_containers_running() {
docker ps --format '{{.Names}}' | grep -q '^GITEA-ACTIONS-TASK-'
}
disable_legacy_docker_runner() {
if ! docker ps -a --format '{{.Names}}' | grep -qx 'gitea-runner'; then
return 0
fi
echo "Disabling legacy docker-wrapped gitea-runner container"
docker update --restart=no gitea-runner >/dev/null 2>&1 || true
if gitea_task_containers_running; then
echo "Active Gitea Actions task containers are running; sending SIGINT to drain gitea-runner" >&2
docker kill --signal=SIGINT gitea-runner >/dev/null 2>&1 || true
return 0
fi
docker stop -t "${LEGACY_RUNNER_STOP_TIMEOUT_SECONDS}" gitea-runner >/dev/null 2>&1 || true
}
if [ ! -x "${RUNNER_DIR}/act_runner" ]; then
echo "act_runner binary not found: ${RUNNER_DIR}/act_runner" >&2
exit 1
fi
if [ ! -f "${CONFIG_FILE}" ]; then
echo "act_runner config not found: ${CONFIG_FILE}" >&2
exit 1
fi
python3 - "${CONFIG_FILE}" "${SHUTDOWN_TIMEOUT}" <<'PY'
import sys
from pathlib import Path
path = Path(sys.argv[1])
shutdown_timeout = sys.argv[2]
lines = path.read_text().splitlines()
in_runner = False
runner_indent = None
insert_at = None
found = False
updated = []
for idx, line in enumerate(lines):
stripped = line.strip()
if stripped == "runner:":
in_runner = True
runner_indent = len(line) - len(line.lstrip())
insert_at = idx + 1
updated.append(line)
continue
if in_runner:
indent = len(line) - len(line.lstrip())
if stripped and indent <= runner_indent:
if not found and insert_at is not None:
updated.insert(insert_at, f" shutdown_timeout: {shutdown_timeout}")
found = True
in_runner = False
elif stripped.startswith("shutdown_timeout:"):
updated.append(f" shutdown_timeout: {shutdown_timeout}")
found = True
continue
elif stripped.startswith("timeout:") or stripped.startswith("capacity:"):
insert_at = len(updated) + 1
updated.append(line)
if in_runner and not found and insert_at is not None:
updated.insert(insert_at, f" shutdown_timeout: {shutdown_timeout}")
found = True
if not found:
raise SystemExit("runner section not found in config")
path.write_text("\n".join(updated) + "\n")
PY
disable_legacy_docker_runner
install_system_service() {
sudo install -o root -g root -m 0644 "${SYSTEM_SERVICE_SRC}" "/etc/systemd/system/${SERVICE_NAME}"
sudo systemctl daemon-reload
sudo systemctl enable "${SERVICE_NAME}" >/dev/null
}
install_user_service() {
local user_service_dir="${HOME}/.config/systemd/user"
mkdir -p "${user_service_dir}"
install -m 0644 "${USER_SERVICE_SRC}" "${user_service_dir}/${SERVICE_NAME}"
systemctl --user daemon-reload
systemctl --user enable "${SERVICE_NAME}" >/dev/null
}
stop_existing_runner() {
if pgrep -u "${RUNNER_USER}" -f "${RUNNER_DIR}/act_runner daemon" >/dev/null; then
pkill -INT -u "${RUNNER_USER}" -f "${RUNNER_DIR}/act_runner daemon" || true
for _ in $(seq 1 60); do
pgrep -u "${RUNNER_USER}" -f "${RUNNER_DIR}/act_runner daemon" >/dev/null || return 0
sleep 1
done
echo "Existing act_runner daemon did not stop within 60s" >&2
return 1
fi
}
if sudo -n true >/dev/null 2>&1; then
SERVICE_SCOPE="system"
install_system_service
else
SERVICE_SCOPE="user"
install_user_service
fi
if [ "${RESTART_NOW:-0}" = "1" ]; then
if gitea_task_containers_running; then
echo "Refusing to restart: Gitea Actions task containers are running" >&2
exit 1
fi
stop_existing_runner
if [ "${SERVICE_SCOPE}" = "system" ]; then
sudo systemctl restart "${SERVICE_NAME}"
else
systemctl --user restart "${SERVICE_NAME}"
fi
elif pgrep -u "${RUNNER_USER}" -f "${RUNNER_DIR}/act_runner daemon" >/dev/null; then
echo "Existing act_runner daemon is still running; service will take over after the next safe restart."
else
if [ "${SERVICE_SCOPE}" = "system" ]; then
sudo systemctl start "${SERVICE_NAME}"
else
systemctl --user start "${SERVICE_NAME}"
fi
fi
if [ "${SERVICE_SCOPE}" = "system" ]; then
sudo systemctl --no-pager --full status "${SERVICE_NAME}" | sed -n '1,18p' || true
else
systemctl --user --no-pager --full status "${SERVICE_NAME}" | sed -n '1,18p' || true
fi
grep -n 'shutdown_timeout' "${CONFIG_FILE}"