Scheduling
Queuety has built-in support for recurring jobs. Instead of relying on wp_cron, schedules are stored in the database and evaluated by the worker process on each tick.
Interval scheduling
Use every() for simple interval-based schedules. The expression is any string compatible with PHP's DateTimeImmutable::modify():
use Queuety\Queuety;
Queuety::schedule( 'cleanup_handler' )
->every( '1 hour' )
->on_queue( 'maintenance' );
Queuety::schedule( 'sync_inventory' )
->every( '30 minutes' )
->on_queue( 'sync' );
Queuety::schedule( 'daily_report', [ 'type' => 'summary' ] )
->every( '1 day' );Cron scheduling
Use cron() for standard 5-field cron expressions:
// Every day at 3am
Queuety::schedule( 'nightly_cleanup' )
->cron( '0 3 * * *' );
// Every Monday at 9am
Queuety::schedule( 'weekly_digest' )
->cron( '0 9 * * 1' )
->on_queue( 'emails' );
// Every 15 minutes
Queuety::schedule( 'health_check' )
->cron( '*/15 * * * *' );Schedule options
The PendingSchedule builder supports these methods:
| Method | Description |
|---|---|
every( string $interval ) | Set an interval expression |
cron( string $expression ) | Set a cron expression |
on_queue( string $queue ) | Set the target queue (default: 'default') |
overlap( OverlapPolicy $policy ) | Set the overlap policy (default: Allow) |
You must call either every() or cron() before the schedule dispatches. If neither is set, a RuntimeException is thrown.
Overlap policies
When a scheduled job is still running (pending or processing) at the time the next tick fires, the overlap policy determines what happens. Set it with the overlap() method:
use Queuety\Queuety;
use Queuety\Enums\OverlapPolicy;
Queuety::schedule( 'sync_inventory' )
->every( '5 minutes' )
->overlap( OverlapPolicy::Skip )
->on_queue( 'sync' );The OverlapPolicy enum has three cases:
| Policy | Value | Behavior |
|---|---|---|
OverlapPolicy::Allow | allow | Always dispatch a new job, even if the previous run is still active. This is the default. |
OverlapPolicy::Skip | skip | Skip the current tick if the handler has any pending or processing jobs. The next_run is updated normally so the schedule stays on cadence. |
OverlapPolicy::Buffer | buffer | Do not dispatch now, but push next_run forward so the job is retried on the next tick. This effectively buffers one pending execution until the current run finishes. |
Allow (default)
Multiple instances of the same handler can run concurrently. Use this for idempotent handlers where overlap is harmless.
Queuety::schedule( 'send_heartbeat_ping' )
->every( '1 minute' )
->overlap( OverlapPolicy::Allow );Skip
The tick is silently skipped if the handler is still running. Use this for handlers where running a second instance would be wasteful or cause conflicts.
Queuety::schedule( 'rebuild_search_index' )
->every( '10 minutes' )
->overlap( OverlapPolicy::Skip );Buffer
Similar to Skip, but the next run is rescheduled to the very next tick instead of the next regular interval. Use this when you want to guarantee the job runs as soon as the current instance finishes, without stacking up multiple runs.
Queuety::schedule( 'sync_inventory' )
->every( '5 minutes' )
->overlap( OverlapPolicy::Buffer );How it works
When a schedule is created, Queuety stores it in the queuety_schedules table with the expression, handler, payload, and the next calculated run time.
On each worker tick, the scheduler checks for schedules whose next_run has passed. For each due schedule, it dispatches a new job and updates next_run to the next occurrence.
Managing schedules via CLI
# List all schedules
wp queuety schedule list
# Add a recurring schedule
wp queuety schedule add cleanup_handler --every="1 hour"
wp queuety schedule add nightly_report --cron="0 3 * * *" --queue=reports
# Remove a schedule
wp queuety schedule remove cleanup_handler
# Manually trigger the scheduler
wp queuety schedule runManaging schedules via PHP
// Get the scheduler instance
$scheduler = Queuety::scheduler();
// List all schedules
$schedules = $scheduler->list();
// Remove a schedule by handler name
$scheduler->remove( 'cleanup_handler' );
// Manually trigger a tick
$count = $scheduler->tick();Payload
Schedules can include a static payload that gets passed to each dispatched job:
Queuety::schedule( 'generate_report', [ 'type' => 'daily', 'format' => 'pdf' ] )
->every( '1 day' )
->on_queue( 'reports' );Every time the schedule fires, a new job is dispatched with this payload.