; Supervisor program for the my.itcarrot.com queue worker. ; AlmaLinux + cPanel, supervisor installed via EPEL: config dir is ; /etc/supervisord.d/*.ini (confirmed via `grep include /etc/supervisord.conf`), ; service name is `supervisord`, not `supervisor`. ; ; Uses the full EA4 CLI binary path, NOT bare `php` — for the `kartulirest` ; user, plain `php` resolves to the CGI/FastCGI SAPI, not CLI (confirmed via ; `php -v` showing "(cgi-fcgi)"). Confirmed working CLI binary: ea-php83. ; If the domain's assigned PHP version ever changes (WHM -> MultiPHP Manager), ; update this path to match. ; ; --------------------------------------------------------------------------- ; THIS FILE BEING COMMITTED IS NOT EVIDENCE THAT A WORKER RUNS. ; ADR-043 Decision 4 requires "a process-manager unit committed to the ; repository ... PLUS evidence that a dispatched job completed on the target ; host". This file is only the first half. The second half is: ; bash deploy/bin/queue-probe.sh ; run on the target host. Until that script prints PASS, treat the queue as ; non-functional and keep provider calls in-request under the ADR-043 D4 ; exception. See docs/architecture/RUNBOOK-queue-and-deploy.md. ; ; This file DOES reach the server. Until 2026-08-28 it did not: deploy.yml ; assembled its upload in a scratch directory also called `deploy`, and the ; rsync exclusion written for that scratch directory matched this tracked one ; too. The scratch directory is now `.deploy-build`, and a `Verify operational ; files reached the build tree` step fails the deploy if this file is ever ; dropped in transit again. ; ; Reaching the server is not the same as being installed. Supervisor reads ; /etc/supervisord.d/, not the application tree, so the `sudo cp` below is ; still a real, manual, root-owned step — it just no longer needs an scp from ; a laptop first, because the source path now exists on the host. ; --------------------------------------------------------------------------- ; ; Install alongside other projects' programs without touching them: ; sudo cp deploy/supervisor/my-itcarrot-worker.ini /etc/supervisord.d/my-itcarrot-worker.ini ; sudo supervisorctl reread ; picks up only this new/changed file ; sudo supervisorctl update ; starts only the new program, leaves others running ; ; After every deploy (new code, changed .env/config), the worker must pick the ; change up. deploy.yml does this with `php artisan queue:restart`, which sets a ; cache flag that a running worker notices and then exits cleanly; supervisor ; restarts it because autorestart=true. Do NOT change autorestart to ; `unexpected` — queue:work exits 0 both on --max-time expiry and on ; queue:restart, and `unexpected` would leave the worker down in both cases. [program:my-itcarrot-worker] process_name=%(program_name)s_%(process_num)02d ; --max-time=3600 worker exits hourly; supervisor restarts it. Bounds any ; memory or connection leak without external supervision. ; --memory=192 artisan exits if RSS exceeds this (MB) mid-run. Second belt ; for the same problem; keep it under the PHP CLI memory_limit. ; --tries=3 with --backoff, a failing job is retried three times at ; 10s/30s/60s rather than hot-looping against a dead provider. ; --sleep=3 poll interval when the queue is empty. This is the worst-case ; pickup latency for a new job on an idle worker. command=/opt/cpanel/ea-php83/root/usr/bin/php /home/kartulirest/public_html/my.itcarrot.com/artisan queue:work --queue=default --sleep=3 --tries=3 --backoff=10,30,60 --max-time=3600 --memory=192 directory=/home/kartulirest/public_html/my.itcarrot.com autostart=true autorestart=true ; Consider the program "started" only after it has survived 10s. Without this a ; worker that crashes instantly on boot (bad .env, unreachable DB) is reported ; RUNNING by supervisorctl between respawns, which is the sort of false green ; this runbook exists to prevent. startsecs=10 startretries=5 stopasgroup=true killasgroup=true ; SIGTERM tells queue:work to finish the job in hand and exit. stopwaitsecs is ; how long supervisor waits before SIGKILL, so it must exceed the longest single ; job, NOT the worker's lifetime. It was 3600, which meant `supervisorctl stop` ; could block for an hour. The longest job this app can currently run is an AI ; provider call, capped at 60s by config/ai.php (ADR-043 D4), so 120 is roughly ; double the worst case. Raise it if a genuinely longer job is introduced. stopsignal=TERM stopwaitsecs=120 user=kartulirest numprocs=1 redirect_stderr=true stdout_logfile=/home/kartulirest/public_html/my.itcarrot.com/storage/logs/worker.log stdout_logfile_maxbytes=10MB stdout_logfile_backups=5