# Campaign Worker Cutover

Laravel owns campaign launch and public runtime. The operational worker cutover is controlled by `SOLTEK_CAMPAIGN_WORKER_PRIMARY`.

## Modes

- `legacy`: legacy cron remains primary. Laravel commands only observe and refuse to dispatch.
- `laravel`: Laravel worker is primary. `campaign:worker-readiness --mode=laravel` must pass before use.
- `fallback`: Laravel worker is preferred, but legacy remains the controlled fallback when the Laravel command is unavailable.

## Safe Commands

Inspect runtime health:

```bash
php artisan campaign:runtime-status
php artisan campaign:runtime-status --organization=1
php artisan campaign:runtime-status --send-id=1065 --json
```

Validate cutover readiness:

```bash
php artisan campaign:worker-readiness --mode=laravel
php artisan campaign:worker-readiness --mode=fallback --organization=1 --json
```

Run through Laravel safety guards:

```bash
php artisan campaign:worker-run --dry-run
php artisan campaign:worker-run --send-id=1065 --batch=25 --rate=5
php artisan campaign:worker-run --organization=1 --batch=25 --rate=5
```

The wrapper clamps batch and rate to conservative config values and dispatches the configured Laravel worker only when readiness passes.

## Required Laravel Worker

The default worker command is:

```bash
php artisan campaign:process-sends
```

Safe manual examples:

```bash
php artisan campaign:process-sends --dry-run --json
php artisan campaign:process-sends --send-id=1065 --batch=10 --rate=10 --max-sends=1 --run-seconds=45 --json
php artisan campaign:process-sends --organization=1 --batch=25 --rate=10 --max-sends=1 --run-seconds=45
```

Configure a different command with:

```bash
SOLTEK_CAMPAIGN_WORKER_COMMAND=campaign:process-sends
```

## Cron Cutover

Laravel primary cron:

```bash
* * * * * cd /var/www/html/soltek-laravel && /usr/bin/flock -n /tmp/soltek_mail_laravel_worker.lock /usr/bin/timeout 75s /usr/bin/php artisan campaign:worker-run --batch=25 --rate=10 >> /tmp/soltek_mail_laravel_worker.log 2>&1
```

Keep the legacy worker line available for rollback, but do not run both global crons unless you are intentionally draining with recipient locks and tight limits.

## Rollback

Set the primary back to legacy and clear config cache:

```bash
SOLTEK_CAMPAIGN_WORKER_PRIMARY=legacy
php artisan config:clear
php artisan optimize:clear
```

Keep or restore the legacy cron:

```bash
* * * * * /usr/bin/flock -n /tmp/soltek_mail_legacy_worker.lock /usr/bin/timeout 120s /usr/bin/php /var/www/html/emkt/cron_worker.php >> /tmp/soltek_mail_legacy_worker.log 2>&1
```

Do not delete legacy until Laravel sends, retry handling, locks, and delivery metrics have passed a full production window.
