#!/bin/bash
# Restart the build instance onto a newer binary, but never mid-build.
#
# Both instances run /usr/local/bin/zuka, so a deploy has already replaced the file
# the build instance started from — it just carries on running the old inode until
# something restarts it. The deploy cannot do that itself: the CI run that asked for
# the deploy is executing inside the build instance, and restarting it would kill the
# run half way through reading the deploy's own result.
#
# So this waits for idle instead. The wait is bounded without needing a ceiling,
# because a run cannot outlive the CI timeout — unlike a tenant, which can be busy
# indefinitely and therefore does need one.
#
# Install:
#   sudo install -o root -g root -m 0755 zuka-build-refresh /usr/local/bin/
#   sudo install -o root -g root -m 0644 zuka-build-refresh.{service,timer} \
#       /etc/systemd/system/
#   sudo systemctl enable --now zuka-build-refresh.timer

set -euo pipefail

readonly SERVICE="zuka-build"
readonly JOBS="zuka-build-jobs"
readonly INSTALLED="/usr/local/bin/zuka"
readonly HEALTH="http://127.0.0.1:8791/healthz"

log() { printf '[refresh] %s\n' "$*" >&2; }

health="$(curl -fsS --max-time 5 "$HEALTH" 2>/dev/null)" || {
	# Down or still starting. Not this script's problem: systemd restarts the unit,
	# and restarting it again here would only add noise to a service already
	# flapping.
	log "$SERVICE is not answering; leaving it alone"
	exit 0
}

running="$("$INSTALLED" version 2>/dev/null | awk '{print $NF}')" || {
	log "the installed binary does not run; refusing to restart onto it"
	exit 1
}

# What the live process reports, which is the binary it actually started from.
if [[ $health == *"$running"* ]]; then
	exit 0
fi

# A build is in flight. Try again on the next tick rather than killing it.
if [[ $health != *'"ci_running":0'* ]]; then
	log "a run is in flight; deferring the restart to $running"
	exit 0
fi

log "restarting onto $running"
systemctl restart "$SERVICE" "$JOBS"
