Skip to content

Add database-backed job queue with WP-Cron and loopback workers - #16

Merged
ahamed merged 1 commit into
mainfrom
feat/scheduler
Sep 28, 2026
Merged

ahamed merged 1 commit into
mainfrom
feat/scheduler

Conversation

@ahamed

@ahamed ahamed commented Sep 28, 2026

Copy link
Copy Markdown
Collaborator

Adds a Laravel-style queue for plugins built on the framework, designed for WordPress hosting where no queue:work daemon can run.

Job API

  • ShouldQueue contract and Queueable trait; a job is a class with handle(), whose class-typed parameters are resolved from the container.
  • Job::dispatch(...) returns a pending dispatch written on destruction, with delay(), on_queue() and with_priority(); plus dispatch_if, dispatch_unless and dispatch_sync.
  • Inside handle(): attempts(), release($delay) and fail($e).
  • $tries, $backoff (seconds or per-attempt array) and failed(Throwable).

Storage and processing

  • Jobs live in app-prefixed {prefix}jobs / {prefix}failed_jobs tables, so several framework plugins on one site never share a queue.
  • Workers claim batches atomically with a single tokened UPDATE ... ORDER BY priority DESC ... LIMIT n, work within a time budget, hand back unstarted jobs without using an attempt, and reclaim reservations older than retry_after so a crashed worker cannot strand a job.
  • An every-minute WP-Cron sweep and a shutdown spawn after undelayed dispatches start an HMAC-signed, non-blocking admin-ajax loopback worker that daisy-chains until the queue is empty. One chain runs at a time.

Opt-in and tooling

  • Enabled only by registering QueueServiceProvider; without it nothing is hooked and dispatch throws a helpful QueueException.
  • Queue facade (push, later, size, clear) and Queue::fake() with assert_pushed, assert_pushed_times, assert_not_pushed, assert_nothing_pushed.
  • JobQueued, JobProcessing, JobProcessed, JobFailed events; failures are also logged.
  • WP-CLI: queue:table (generates migrations, runs no DDL), make:job, queue:work, queue:failed, queue:retry, queue:forget, queue:flush, queue:clear.
  • docs/queues.md, including the blocked-loopback / low-traffic fallback and where this differs from Laravel; optional config/queue.php in the example.

Also records the grilling preference in CLAUDE.md.

New public API is tagged @SInCE 3.2.0.

Adds a Laravel-style queue for plugins built on the framework, designed for
WordPress hosting where no `queue:work` daemon can run.

Job API
- `ShouldQueue` contract and `Queueable` trait; a job is a class with
  `handle()`, whose class-typed parameters are resolved from the container.
- `Job::dispatch(...)` returns a pending dispatch written on destruction, with
  `delay()`, `on_queue()` and `with_priority()`; plus `dispatch_if`,
  `dispatch_unless` and `dispatch_sync`.
- Inside `handle()`: `attempts()`, `release($delay)` and `fail($e)`.
- `$tries`, `$backoff` (seconds or per-attempt array) and `failed(Throwable)`.

Storage and processing
- Jobs live in app-prefixed `{prefix}jobs` / `{prefix}failed_jobs` tables, so
  several framework plugins on one site never share a queue.
- Workers claim batches atomically with a single tokened
  `UPDATE ... ORDER BY priority DESC ... LIMIT n`, work within a time budget,
  hand back unstarted jobs without using an attempt, and reclaim reservations
  older than `retry_after` so a crashed worker cannot strand a job.
- An every-minute WP-Cron sweep and a shutdown spawn after undelayed
  dispatches start an HMAC-signed, non-blocking admin-ajax loopback worker that
  daisy-chains until the queue is empty. One chain runs at a time.

Opt-in and tooling
- Enabled only by registering `QueueServiceProvider`; without it nothing is
  hooked and dispatch throws a helpful `QueueException`.
- `Queue` facade (`push`, `later`, `size`, `clear`) and `Queue::fake()` with
  `assert_pushed`, `assert_pushed_times`, `assert_not_pushed`,
  `assert_nothing_pushed`.
- `JobQueued`, `JobProcessing`, `JobProcessed`, `JobFailed` events; failures
  are also logged.
- WP-CLI: `queue:table` (generates migrations, runs no DDL), `make:job`,
  `queue:work`, `queue:failed`, `queue:retry`, `queue:forget`, `queue:flush`,
  `queue:clear`.
- `docs/queues.md`, including the blocked-loopback / low-traffic fallback and
  where this differs from Laravel; optional `config/queue.php` in the example.

Also records the grilling preference in CLAUDE.md.

New public API is tagged @SInCE 3.2.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ahamed
ahamed merged commit fad01c7 into main Sep 28, 2026
1 check passed
@ahamed
ahamed deleted the feat/scheduler branch September 28, 2026 13:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant