Skip to content

Scheduler trait

Barberklingen\BasePlugin\Traits\Scheduler

Wraps the Action Scheduler library to provide recurring background jobs with a distributed process lock.

Usage

use Barberklingen\BasePlugin\Traits\Scheduler;

class MyBackgroundJob {
    use Scheduler;

    public function scheduler_name(): string {
        return 'my-plugin/my-background-job';
    }

    public function scheduler_interval(): int {
        return HOUR_IN_SECONDS; // run every hour
    }

    public function scheduler_logic(): void {
        // Your business logic here.
        // Only one instance runs at a time — the lock is held for up to
        // get_process_lock_in_minutes() (default: 5).
    }
}

MyBackgroundJob::get_instance();

How the lock works

The lock is stored in wp_options with autoload = no to prevent WordPress from loading it into the object cache on boot. The raw value is read directly from the database ($wpdb) to bypass Redis or other persistent object caches — this prevents a stale cache entry from making the lock appear permanently active.

Lock key:  {scheduler_name}_lock
Lock value: Unix timestamp (when the lock was set)
Lock TTL:  get_process_lock_in_minutes() × MINUTE_IN_SECONDS (default: 5 min)

If a process fails before releasing the lock, the next run after the TTL expires will proceed normally.

Execution flow

sequenceDiagram
    participant CJ as cron.org / Action Scheduler
    participant S as Scheduler trait
    participant DB as wp_options (bypasses object cache)

    CJ->>S: system_cron_job_org action
    S->>S: maybe_start_scheduler()
    note over S: registers recurring AS action if not already scheduled
    CJ->>S: {scheduler_name} action (fired by Action Scheduler)
    S->>DB: read lock directly (no cache)
    alt lock free or expired
        S->>DB: write lock (timestamp)
        S->>S: scheduler_logic()
        S->>DB: delete lock + clear cache
    else already running
        S-->>CJ: SchedulerAlreadyRunningException (NOOP)
    end

Configuration

Method Default Description
scheduler_name() (required) Action Scheduler action name
scheduler_interval() (required) Interval in seconds
scheduler_logic() (required) Business logic
get_process_lock_in_minutes() 5 Override to allow longer jobs
is_multiple_crons_allowed() false Set true to disable the lock

Checking the next run

$timestamp = MyBackgroundJob::get_instance()->next_event_timestamp();
// returns false if not scheduled

Registering via cron.org

The system_cron_job_org WordPress action is fired by the CronEndpoint module when cron.org calls the wp-admin/admin-ajax.php?action=system_cron_job_org endpoint. The Scheduler trait hooks into this action to call maybe_start_scheduler(), ensuring the Action Scheduler recurring action is registered on the first run.