# Dedicated WooCommerce media worker

Dropleather 1.1.8 registers media work through REST and consumes it only through WP-CLI. Do not run this command through WP-Cron, Action Scheduler's loopback runner, Apache, nginx, or PHP-FPM.

## Required topology

Run `bin/run-media-worker.sh` as a separately supervised process with the same WordPress database and the same `wp-content/uploads` filesystem as the web container. One worker process is the safe initial setting for a three-slot PHP-FPM store. Scale to two only after CPU, memory, disk I/O, and p95 site latency remain healthy.

The worker may share a container with Apache/PHP-FPM if the process supervisor gives it independent process and memory limits; it does not consume a PHP-FPM request slot. A separate Railway service is safe only when it mounts the exact same uploads volume. A database-only clone is unsafe because attachment rows would point to files unavailable to the web service.

Example worker command:

```sh
WORDPRESS_PATH=/var/www/html \
DROPLEATHER_MEDIA_WORKER_SLEEP=2 \
DROPLEATHER_MEDIA_WORKER_MAX_RUNTIME=3600 \
./wp-content/plugins/dropleather-for-woocommerce/bin/run-media-worker.sh
```

Health check:

```sh
wp --path=/var/www/html option get dropleather_media_worker_heartbeat
```

The timestamp must advance at least once per minute. Plugin heartbeats report this state to Dropleather. The backend enables async export for that store only when all three gates are true:

For a container health check, use:

```sh
WORDPRESS_PATH=/var/www/html \
./wp-content/plugins/dropleather-for-woocommerce/bin/media-worker-healthcheck.sh
```

1. API environment `WC_EXPORT_ENGINE=canonical-v3`.
2. The canary integration has `async_export_v3_enabled=true`.
3. Plugin version is 1.1.8 or newer and has a bridge secret.
4. The dedicated WP-CLI heartbeat is less than 60 seconds old, which sets `async_export_v3_capable=true`.

Capability never enables rollout by itself. This prevents a plugin heartbeat from accidentally bypassing the canary gate.

## Railway process contract

Create a dedicated worker service from the same WordPress image and database configuration. Its start command is:

```sh
/var/www/html/wp-content/plugins/dropleather-for-woocommerce/bin/run-media-worker.sh
```

It must mount the same persistent `/var/www/html/wp-content/uploads` volume as the web service. Configure the health command above, restart policy `on-failure`, and a termination grace period greater than five minutes. Do not expose an HTTP port from this service. The WordPress web service continues running Apache/PHP-FPM; the worker service runs only WP-CLI.

Stopping the CLI worker automatically disables new canonical-v3 dispatches on the next plugin heartbeat. Durable tasks remain in Postgres and WordPress; they are not marked successful.

## Resource limits and health

- Start with one CLI worker per store.
- Reserve the existing web/PHP workers for REST and interactive traffic.
- Alert when the heartbeat is older than 90 seconds.
- Alert when the oldest queued media task exceeds five minutes.
- Restart the CLI process after one hour; checkpoints make rotation safe.
- Never use a process-kill timeout shorter than the worker's three-minute task lease.

## Rollback

Set the canary integration's `async_export_v3_enabled=false` first. Do not change `engine_version` on existing jobs and do not delete durable tasks. Existing canonical jobs remain pinned to V3 and must drain or be cancelled explicitly. Set `WC_EXPORT_ENGINE=legacy-v2` only for new-job rollback after those jobs are accounted for.
