ultimate-multisite/the-perfect-wp-cron
最新稳定版本:v1.0.1
Composer 安装命令:
composer require ultimate-multisite/the-perfect-wp-cron
包简介
Event-loop job queue for WordPress. Executes WP Cron and Action Scheduler jobs at exact scheduled times with zero polling.
README 文档
README
Upload the zip to WordPress like any other plugin
Event-loop job queue for WordPress. Replaces WP-Cron's poll-on-visit model and system cron's once-per-minute limitation with a long-running Workerman process that executes every WP Cron event and Action Scheduler action at its exact scheduled time — zero polling, zero delay.
Who Is It For
- Multisite operators running dozens or hundreds of sites where missed cron events and overlapping runners are a constant problem.
- Hosting providers who need predictable, observable background processing without per-site cron entries.
- Sites with heavy Action Scheduler workloads (WooCommerce Subscriptions, background imports, bulk email) that need parallel execution with per-job timeouts.
- Anyone who needs precise scheduling — if a job is scheduled for 14:32:07, it runs at 14:32:07, not whenever the next visitor arrives or the next minute ticks over.
Advantages Over WP-Cron
| WP-Cron | The Perfect WP Cron |
|---|---|
| Triggers on page visits — low-traffic sites miss schedules | Triggers at exact scheduled time via event-loop timer |
| Adds latency to a visitor's request | Runs in a separate process — zero impact on web requests |
| Single-threaded — one job at a time | Configurable parallel workers and concurrency |
| No timeout protection | Per-job SIGALRM timeout stops runaway jobs |
| No visibility into what ran or failed | Admin dashboard + per-job log table with duration and errors |
Advantages Over System Cron
System Cron (* * * * *) |
The Perfect WP Cron |
|---|---|
| Minimum 1-minute granularity | Sub-second precision via Workerman timers |
| Polls the database every minute even if nothing is due | Socket notification — the worker knows instantly when a new job is scheduled |
| One WP bootstrap per cron run | Batches jobs by site — multiple jobs share one WP bootstrap |
| Separate cron entry per site (multisite) | Single process handles all sites in the network |
| No built-in concurrency | Configurable worker count and max concurrent subprocesses |
| No automatic restart | Uptime + memory watchdog, designed for systemd auto-restart |
Disadvantages
- Requires CLI/SSH access. You need to run a long-lived PHP process, typically via systemd. Shared hosting without shell access won't work.
- Linux only. Workerman requires
pcntl_forkandpcntl_signal, which are not available on Windows or macOS in production. - Workerman dependency. Adds ~200KB to your vendor directory. The process must be managed (started, monitored, restarted) outside of WordPress.
- More complex than default cron. There's a process to monitor. If it stops unexpectedly and systemd isn't configured, jobs won't run until someone notices.
- Socket communication. The web server's PHP process must be able to write to the Unix socket. File permissions matter.
Requirements
- PHP 8.1+
pcntlextension (standard on Linux, verify withphp -m | grep pcntl)- Linux (Workerman uses
pcntl_fork) - WordPress 6.0+
- Composer
Installation
Via Composer (recommended)
Add the repository and require the package:
{
"repositories": [
{
"type": "vcs",
"url": "https://github.com/Ultimate-Multisite/the-perfect-wp-cron.git"
}
],
"require": {
"ultimate-multisite/the-perfect-wp-cron": "dev-main"
}
}
Then run:
composer update ultimate-multisite/the-perfect-wp-cron
The plugin installs to wp-content/plugins/the-perfect-wp-cron/ (or web/app/plugins/ on Bedrock).
Manual Installation
Clone into your plugins directory and install the Workerman dependency:
cd wp-content/plugins git clone https://github.com/Ultimate-Multisite/the-perfect-wp-cron.git cd the-perfect-wp-cron composer install --no-dev
Activate the plugin in wp-admin (or network-activate on multisite).
Configuration
Every setting can be configured via PHP constant (in wp-config.php) or environment variable. Constants take priority over env vars. All settings have sensible defaults — zero configuration is required to get started.
| Constant / Env Var | Default | Description |
|---|---|---|
QUEUE_WORKER_SOCKET_PATH |
/tmp/the-perfect-wp-cron.sock |
Unix socket path |
QUEUE_WORKER_COUNT |
2 |
Number of worker processes (Workerman forks) |
QUEUE_WORKER_MAX_CONCURRENT |
1 |
Max concurrent subprocesses per worker |
QUEUE_WORKER_MAX_BATCH_SIZE |
50 |
Max jobs per subprocess batch |
QUEUE_WORKER_JOB_TIMEOUT |
300 |
Per-job timeout in seconds (SIGALRM) |
QUEUE_WORKER_BATCH_TIMEOUT |
3600 |
Subprocess timeout in seconds (safety net) |
QUEUE_WORKER_RESCAN_INTERVAL |
60 |
Seconds between database rescans |
QUEUE_WORKER_MEMORY_LIMIT |
200 |
Memory limit in MB before auto-restart |
QUEUE_WORKER_UPTIME_LIMIT |
3600 |
Max uptime in seconds before auto-restart |
QUEUE_WORKER_LOG_FILE |
auto-detect | Path to log for admin viewer |
QUEUE_WORKER_LOG_RETENTION |
7 |
Days to keep job log entries |
DOMAIN_CURRENT_SITE |
localhost |
Primary domain for WP bootstrap in worker |
WP_ROOT_PATH |
auto-detect | Path to directory containing wp-load.php |
Example wp-config.php:
define('QUEUE_WORKER_SOCKET_PATH', '/run/the-perfect-wp-cron.sock'); define('QUEUE_WORKER_COUNT', 4); define('QUEUE_WORKER_JOB_TIMEOUT', 600); define('QUEUE_WORKER_LOG_FILE', '/var/log/the-perfect-wp-cron.log');
Usage
Starting the Worker
# Foreground (for debugging) php wp-content/plugins/the-perfect-wp-cron/bin/worker.php start # Daemonized php wp-content/plugins/the-perfect-wp-cron/bin/worker.php start -d # Stop / Restart / Status php wp-content/plugins/the-perfect-wp-cron/bin/worker.php stop php wp-content/plugins/the-perfect-wp-cron/bin/worker.php restart php wp-content/plugins/the-perfect-wp-cron/bin/worker.php status
Bedrock: replace wp-content/plugins with web/app/plugins.
systemd Service (Production)
Create /etc/systemd/system/the-perfect-wp-cron.service:
[Unit] Description=WordPress Queue Worker After=network.target mariadb.service [Service] Type=simple User=www-data Group=www-data WorkingDirectory=/var/www/example.com/current ExecStart=/usr/bin/php web/app/plugins/the-perfect-wp-cron/bin/worker.php start Restart=always RestartSec=5 StandardOutput=append:/var/log/the-perfect-wp-cron.log StandardError=append:/var/log/the-perfect-wp-cron-error.log MemoryMax=1G Environment=WP_ENV=production Environment=QUEUE_WORKER_COUNT=4 [Install] WantedBy=multi-user.target
sudo systemctl enable the-perfect-wp-cron
sudo systemctl start the-perfect-wp-cron
WP-CLI Commands
wp queue status # Show worker PID, uptime, memory, pending/running jobs wp queue populate # Rescan — send all pending jobs to the worker wp queue restart # Graceful restart (systemd auto-restarts)
Admin Dashboard
After activating the plugin, a Queue Worker page appears under:
- Network Admin > Settings (multisite)
- Tools (single site)
The dashboard shows:
- Worker Status — running/stopped, PID, uptime, memory, currently executing jobs. Auto-refreshes every 10 seconds.
- Per-Site Resource Usage — which sites consume the most CPU time over the last 24 hours.
- Job History — searchable, filterable, sortable log of every executed job with status, duration, and error messages.
- Recent Log Entries — tail of the worker log.
Architecture
WordPress Request Worker Process (Workerman)
+---------------------------+ +------------------------------------+
| Cron_Interceptor | | Event loop (libevent/select) |
| hooks schedule_event |------->| Unix socket listener |
| | socket | Timer per job (exact timestamp) |
| Action_Scheduler_Bridge | | Periodic DB rescan (safety net) |
| hooks stored_action |------->| Memory + uptime watchdog |
+---------------------------+ +------------------------------------+
|
Timer triggers at scheduled time
|
Claim job (INSERT IGNORE lock)
|
Batch by site_id
|
+------------------------------+
| Subprocess: execute-job.php |
| Bootstrap WP for site |
| For each job in batch: |
| SIGALRM timeout guard |
| Run hook / AS action |
| Log result to qw_job_log |
+------------------------------+
Flow:
- WordPress schedules a cron event or Action Scheduler action.
- The plugin intercepts the schedule call and sends a JSON payload to the worker via Unix socket.
- The worker sets a Workerman timer for the job's exact timestamp.
- When the timer triggers, the worker atomically claims the job via
INSERT IGNOREinto a lock table (prevents duplicate execution across workers). - Claimed jobs are batched by
site_idand flushed to a subprocess every second. - The subprocess (
execute-job.php) bootstraps WordPress for the target site's domain, executes each job with a per-job SIGALRM timeout, logs results to theqw_job_logtable, and exits. - The worker polls subprocesses for completion and logs batch results.
- A periodic database rescan catches any jobs that arrived before the worker started or bypassed socket notification.
Troubleshooting
Worker won't start — "Address already in use"
A leftover socket exists. The worker tries to clean it up automatically, but if another process holds it: rm /tmp/the-perfect-wp-cron.sock (or your configured path).
Jobs aren't executing
- Check
wp queue status— is the worker running? - Check
wp queue populate— does it find pending jobs? - Check the worker log for errors.
- Verify the web server user can write to the socket path.
"Could not find wp-load.php"
Set the WP_ROOT_PATH environment variable to the directory containing wp-load.php (for standard WP) or web/wp/wp-load.php's parent (Bedrock auto-detected).
Socket permission denied
The worker creates the socket with mode 0660. Ensure the web server user (www-data) and the worker process user are in the same group, or configure the socket path to a directory both can access.
Per-job timeout stops a legitimate long-running job
Increase QUEUE_WORKER_JOB_TIMEOUT (default 300 seconds). For specific hooks that need more time, consider breaking the work into smaller chunks.
High memory usage / frequent restarts
The watchdog restarts workers when memory exceeds QUEUE_WORKER_MEMORY_LIMIT (default 200 MB) or uptime exceeds QUEUE_WORKER_UPTIME_LIMIT (default 3600 seconds). These are safety nets — increase them if your workload legitimately needs more resources, or investigate memory leaks in the jobs themselves.
License
GPL-2.0-or-later. See LICENSE.
统计信息
- 总下载量: 6
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 11
- 点击次数: 5
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: GPL-2.0-or-later
- 更新时间: 2026-03-03