#!/usr/bin/env bash
#
# FALLBACK queue runner for hosts where supervisord is not usable.
#
# ---------------------------------------------------------------------------
# THIS IS THE SECOND CHOICE. Use deploy/supervisor/my-itcarrot-worker.ini first.
#
# The evidence in this repository says supervisor IS available on the target
# host: deploy/supervisor/*.ini record that it was installed from EPEL, that the
# include directory is /etc/supervisord.d/*.ini (confirmed on the host with
# `grep include /etc/supervisord.conf`), and that the service is `supervisord`.
# The Reverb program in the same directory is configured the same way. A
# long-running supervised worker picks a job up in ~0s; this script picks it up
# in up to ~60s. Do not adopt this one because it looks simpler.
#
# Use this ONLY if `sudo supervisorctl status` is unavailable to the operator —
# e.g. the account loses root, or the host is migrated to shared cPanel where
# supervisord cannot be installed.
#
# DO NOT RUN BOTH. Two runners are not harmful to correctness (the database
# queue driver locks rows, so a job is not executed twice) but they waste PHP
# processes and make "is the worker healthy?" unanswerable. Pick one.
# ---------------------------------------------------------------------------
#
# Install as a cPanel cron job (cPanel -> Cron Jobs), every minute:
#
#   * * * * * /home/kartulirest/public_html/my.itcarrot.com/deploy/cron/queue-worker-fallback.sh >> /home/kartulirest/public_html/my.itcarrot.com/storage/logs/queue-cron.log 2>&1
#
# Accepted limitations, stated plainly so nobody is surprised later:
#   * Pickup latency is up to ~60s. One minute is the finest granularity cron
#     offers. A user pressing a button that queues work waits up to a minute
#     before anything begins. This is why it is the fallback.
#   * There is no instant pickup and no restart-on-crash. If a run dies, nothing
#     notices; the next minute simply starts a new one.
#   * `queue:restart` has no useful effect here — each run is a fresh process
#     that already loads current code, so it picks changes up on its own.
#   * Throughput is bounded by one process at a time (flock). Long jobs delay
#     the queue behind them.
#
# The verification procedure is identical either way: deploy/bin/queue-probe.sh
# must print PASS. Allow for the latency above — run it with PROBE_TIMEOUT=180.

set -uo pipefail

APP_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
LOCK_FILE="$APP_ROOT/storage/framework/queue-worker.lock"

# --max-time=55 keeps a run inside its own minute, so runs do not pile up.
# --stop-when-empty exits as soon as the queue drains instead of idling for 55s,
# which matters on shared hosting where process-count limits are enforced.
# --max-jobs bounds a single run so one busy minute cannot monopolise the slot.
MAX_TIME=55
MAX_JOBS=100

cd "$APP_ROOT" || exit 1

# Same CLI-php resolution as deploy.yml and queue-probe.sh: bare `php` on this
# cPanel account can be the CGI/FastCGI SAPI, which cannot run artisan. cron's
# environment is even more minimal than an interactive shell's, so this matters
# more here, not less.
PHP=""
for CANDIDATE in \
  /opt/cpanel/ea-php83/root/usr/bin/php \
  /opt/cpanel/ea-php84/root/usr/bin/php \
  "$(command -v php 2>/dev/null || true)"
do
  [ -n "$CANDIDATE" ] || continue
  [ -x "$CANDIDATE" ] || continue
  if [ "$("$CANDIDATE" -r 'echo PHP_SAPI;' 2>/dev/null)" = "cli" ]; then
    PHP="$CANDIDATE"
    break
  fi
done

if [ -z "$PHP" ]; then
  echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) FATAL: no PHP binary reporting SAPI 'cli'; queue not drained." >&2
  exit 1
fi

RUN="$PHP artisan queue:work --queue=default --stop-when-empty --max-time=$MAX_TIME --max-jobs=$MAX_JOBS --tries=3 --backoff=10,30,60 --memory=192"

# Serialise runs. Without this, a job that outlives its minute leaves overlapping
# workers accumulating once per minute until the host runs out of processes.
# -n = fail immediately rather than queue up behind the running instance.
if command -v flock >/dev/null 2>&1; then
  exec flock -n "$LOCK_FILE" $RUN
fi

# flock absent (unusual on AlmaLinux; util-linux provides it). Fall back to a
# PID-file guard. This is racier than flock but far better than nothing.
echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) WARN: flock not found; using PID-file guard." >&2
PID_FILE="$APP_ROOT/storage/framework/queue-worker.pid"
if [ -f "$PID_FILE" ] && kill -0 "$(cat "$PID_FILE" 2>/dev/null)" 2>/dev/null; then
  exit 0
fi
echo $$ > "$PID_FILE"
trap 'rm -f "$PID_FILE"' EXIT
exec $RUN
