| 1 |
# LiteSpeed async queue workers |
| 2 |
|
| 3 |
The jobs runner sends a nonblocking request to |
| 4 |
`wp-admin/admin-ajax.php?action=sync_basalam_run_jobs_async`. The caller closes |
| 5 |
the connection before the worker finishes. On LiteSpeed, `ignore_user_abort(true)` |
| 6 |
does not prevent the server from aborting that worker. |
| 7 |
|
| 8 |
Install this block near the top of the site's document-root `.htaccess`, before |
| 9 |
other rewrite rules. Back up the existing file first. The rule applies only to |
| 10 |
the plugin's async action; the AJAX nonce check, PHP execution limit and runner |
| 11 |
database lock still apply. |
| 12 |
|
| 13 |
```apache |
| 14 |
# BEGIN SyncBasalam Async |
| 15 |
<IfModule LiteSpeed> |
| 16 |
<IfModule mod_rewrite.c> |
| 17 |
RewriteEngine On |
| 18 |
RewriteCond %{REQUEST_URI} /wp-admin/admin-ajax\.php$ |
| 19 |
RewriteCond %{QUERY_STRING} (^|&)action=sync_basalam_run_jobs_async(&|$) |
| 20 |
RewriteRule .* - [E=noabort:1] |
| 21 |
</IfModule> |
| 22 |
</IfModule> |
| 23 |
# END SyncBasalam Async |
| 24 |
``` |
| 25 |
|
| 26 |
This is a host configuration requirement. The plugin does not install this rule |
| 27 |
automatically. Do not apply `noabort` to every site request. |
| 28 |
|
| 29 |
An aborted worker can leave a job in `processing` with no exception recorded. |
| 30 |
The stale-job recovery retries it after 120 seconds and eventually marks it |
| 31 |
failed. This differs from an orphaned dispatch transient, which can prevent any |
| 32 |
worker from starting. The deadline stored in the dispatch lease fixes that |
| 33 |
separate problem. |
| 34 |
|
| 35 |
After applying the rule, verify that the bulk cursor advances, successful jobs |
| 36 |
complete through normal cleanup, and no new stale retries occur. For failed |
| 37 |
product creation jobs, search the vendor's existing products before retrying: |
| 38 |
an earlier request may have created the product before its local mapping was |
| 39 |
saved. Keep historical failures and actual API rejection messages for diagnosis. |
| 40 |
|
| 41 |
References: |
| 42 |
|
| 43 |
- [](https://docs.litespeedtech.com/lsws/extapp/php/configuration/control/LiteSpeed: controlling LSPHP and connection aborts](https://docs.litespeedtech.com/lsws/extapp/php/configuration/control/](https://docs.litespeedtech.com/lsws/extapp/php/configuration/control/) |
| 44 |
- [](https://github.com/litespeedtech/lscache_wp/blob/master/src/htaccess.cls.phpLiteSpeed Cache's own scoped async rewrite rule](https://github.com/litespeedtech/lscache_wp/blob/master/src/htaccess.cls.php](https://github.com/litespeedtech/lscache_wp/blob/master/src/htaccess.cls.php) |
| 45 |
|
| 46 |
## Automatic admin warning |
| 47 |
|
| 48 |
Actual async workers check the effective `noabort` / `REDIRECT_noabort` |
| 49 |
request environment. On the LiteSpeed PHP runtime, an absent flag produces a |
| 50 |
warning on Woosalam, product and order admin screens for users who can manage |
| 51 |
WooCommerce or site options. Absence is reported as unverified protection: |
| 52 |
a global server configuration may protect workers without exposing that flag. |
| 53 |
The plugin never assumes that a LiteSpeed Cache plugin is active and never |
| 54 |
rewrites `.htaccess` itself. |
| 55 |
|
| 56 |
If a job remains `processing` beyond 120 seconds and the runner global MySQL |
| 57 |
lock can be acquired, its previous worker has stopped. The next runner records |
| 58 |
this before stale recovery, and an admin request can also discover it when no |
| 59 |
new worker starts. A live worker retains the lock and cannot trigger this |
| 60 |
interruption warning merely by being slow. Explicit API failures are handled |
| 61 |
separately. The alert includes the job ID, log link, hosting guidance and an |
| 62 |
expandable scoped rewrite rule. |
| 63 |
|
| 64 |
The latest evidence is retained in `sync_basalam_async_worker_health`, with |
| 65 |
`autoload=false` and no payloads, credentials or request headers. Empty or |
| 66 |
contended batches do not clear interruption evidence. On LiteSpeed, a returned |
| 67 |
job clears it only when effective `noabort` was observed; a quick unprotected |
| 68 |
return still leaves the warning visible. On another PHP runtime, a completed |
| 69 |
async execution clears the interruption warning. Detection runs on async |
| 70 |
workers and relevant admin visits; it is not an external push notification. |
| 71 |
|
| 72 |
### Reproducible validation |
| 73 |
|
| 74 |
- `php tests/JobsRunnerLeaseRegression.php` checks the orphaned lease cases. |
| 75 |
- `phpunit --configuration phpunit.xml` runs the unit regression suite. |
| 76 |
- In the local Docker WordPress stack, run `php tests/integration/async-worker-health.php`. |
| 77 |
This uses the real queue and MySQL locks, kills a separate PHP process during |
| 78 |
execution, verifies slow-worker exclusion, stale recovery, admin permissions, |
| 79 |
actionable markup, and separate API rejection. LiteSpeed environment flags |
| 80 |
are simulated in this local Apache environment. |
| 81 |
- `php tests/integration/product-sync-operations.php` exercises actual WooCommerce |
| 82 |
save hooks and product operations against deterministic API response fixtures. |
| 83 |
- Verify automatic AJAX execution against the live host separately; local |
| 84 |
fixtures do not test LiteSpeed's actual connection-abort behavior. |
| 85 |
|