infra/vps: PRAB generation orchestrator (systemd timer, SSH-driven --sync) #27
Reference in New Issue
Block a user
Delete Branch "claude/vps-generation-orchestrator-20260622"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What changed
Adds
infra/vps/— the VPS-side orchestrator for Option A (ADR 2026-06-22): the Coolify KVM8 VPS (76.13.220.15) drives PRAutoBlogger article generation on prod synchronously over a held-open SSH session, escaping Hostinger's ~10-min background-PHP-process kill.Files added
infra/vps/orchestrate-generation.shPRAutoBlogger_Run_Reaper::reap()viawp evalat run start (belt-and-suspenders reaper sweep).wp prautoblogger generate --sync --path=...(requires companion plugin PR v0.22.1).Generation_LockDB mutex prevents double-drive;--syncexits 0 withskippedJSON if a live run is in progress.StandardOutput=journal→journalctl -u prab-generation).cto@peptiderepo.comviamail(forwards to peptiderepo@gmail.com via Cloudflare Email Routing). No external API token needed; systemmailis the alert channel.DRY_RUN=1mode: echoes SSH/WP-CLI commands without executing generation.SSH_KEY,SSH_HOST,SSH_PORT,SSH_USER,WP_PATH); no hardcoded secrets./root/.ssh/hostinger_prod_ed25519) — never embedded.shellcheck-clean (SC2029disable on the SSH command with remote variable expansion).infra/vps/install-orchestrator.sh/opt/prab-orchestrator/, installs.service+.timerto/etc/systemd/system/, runsdaemon-reload.infra/vps/prab-generation.serviceType=oneshot,User=root,TimeoutStartSec=7200(covers 32-min LLM calls observed in prod).Restart=no— timer retries next day on failure.SyslogIdentifier=prab-generationfor clean journal queries.infra/vps/prab-generation.timerOnCalendar=*-*-* 06:00:00 UTC(fires before Hostinger daily wp-cron window).Persistent=true— if VPS was down at 06:00 UTC, fires immediately on next boot.RandomizedDelaySec=300— jitter for future multi-VPS scenarios.Why
Hostinger's shared-hosting plan kills detached background PHP processes at ~10 min (CloudLinux LVE). A single LLM draft call observed 1925s (~32 min). SSH-attached processes survive because they run under a different LVE context. The VPS SSHes to Hostinger and holds the connection open, giving the plugin's engine an unlimited execution window.
Companion plugin PR: peptide-repo/prautoblogger#171 (v0.22.1 — adds
--syncflag).Alerting channel justification
System
mail→cto@peptiderepo.com→ Cloudflare Email Routing →peptiderepo@gmail.com. Chosen because: (1) zero external API tokens required on the VPS, (2) the Cloudflare routing is already live and tested, (3) simpler to operate than a Discord webhook (no token rotation), (4) delivery is reliable for low-frequency critical alerts (~1/day at most). Fallback: journal logs are always available viajournalctl -u prab-generation -n 50.Risk flags
mailbinary may not be installed on the VPS (apt-get install mailutils). The script degrades gracefully (|| log ...) — a missingmaildoes not abort the run./root/.ssh/hostinger_prod_ed25519must exist before production use.install-orchestrator.shvalidates its presence.Test plan
shellcheck infra/vps/orchestrate-generation.sh infra/vps/install-orchestrator.sh— expected: cleanDRY_RUN=1 infra/vps/orchestrate-generation.shon the VPS — expected: echoes SSH commands, no generationjournalctl -u prab-generation -n 20systemctl enable --now prab-generation.timer, verifysystemctl list-timersAgent-Session: prab-reliability-20260622