Introduction
Queuety is a WordPress plugin that provides a fast job queue and durable workflow engine. Workers process jobs from a minimal PHP bootstrap without booting WordPress, connecting to MySQL directly via PDO for maximum throughput.
Why Queuety?
WordPress has no real background job system. wp_cron only fires on page visits. Action Scheduler boots the entire WordPress stack for every batch. An LLM API call that takes 60 seconds gets killed by PHP's 30-second timeout. There's no way to run multi-step processes that survive crashes and resume where they left off.
Queuety solves this with two primitives:
- Jobs for fire-and-forget background work
- Workflows for durable multi-step processes with persistent state
Quick example
Dispatch a job using the modern API:
use Queuety\Contracts\Job;
use Queuety\Dispatchable;
readonly class SendEmailJob implements Job {
use Dispatchable;
public function __construct(
public string $to,
public string $subject,
public string $body,
) {}
public function handle(): void {
wp_mail( $this->to, $this->subject, $this->body );
}
}
SendEmailJob::dispatch( 'user@example.com', 'Welcome', 'Hello from Queuety!' );Or use the classic handler name approach:
use Queuety\Queuety;
Queuety::dispatch( 'send_email', [ 'to' => 'user@example.com' ] );Run a durable workflow:
Queuety::workflow( 'generate_report' )
->then( FetchDataHandler::class )
->then( CallLLMHandler::class )
->then( FormatOutputHandler::class )
->dispatch( [ 'user_id' => 42 ] );Start a worker:
wp queuety workKey differentiators
- Fast execution. Workers skip the WordPress boot, connecting to MySQL directly via PDO. ~5ms overhead per batch vs ~200ms when loading WordPress.
- Durable workflows. Multi-step processes with persistent state that survive PHP timeouts, crashes, and retries. Each step boundary is an atomic MySQL transaction.
- Modern dispatch API. Self-contained readonly job classes with the
Dispatchabletrait, typed constructor properties as payload, and$tries/$timeout/$backoffdeclared on the class. - Middleware pipeline. Onion-style middleware for rate limiting, exception throttling, unique jobs, and custom logic. Declared per-job via a
middleware()method. - Streaming steps. The
StreamingStepinterface yields chunks that are persisted to the database immediately. On retry, previously saved chunks are provided so the stream can resume where it left off. Ideal for LLM responses and large downloads. - Pluggable cache layer.
CacheFactoryauto-detects APCu or falls back to an in-memory cache. Custom backends implementContracts\Cache. Used internally for rate-limiter lookups and queue state. - Batching and chaining. Dispatch groups of jobs with
then/catch/finallycallbacks and progress tracking, or chain jobs sequentially where each depends on the previous one completing. - Durable timers and signals.
sleep()adds process-restart-safe delays.wait_for_signal()pauses a workflow until an external event arrives. - Heartbeats. Long-running steps send heartbeats to prevent the stale-job recovery system from reclaiming active work.
- Workflow event log. Every step transition is recorded with a full state snapshot, enabling time-travel debugging via
workflow_state_at(). - Parallel steps. Run steps concurrently and wait for all to complete before advancing.
- Conditional branching. Skip to named steps based on prior state using
_goto. - Sub-workflows. Spawn child workflows that feed results back to the parent.
- Priority queues. Four levels (Low, Normal, High, Urgent) via type-safe PHP enums.
- Multi-queue workers. Process multiple queues with weighted priority ordering in a single worker.
- Rate limiting. Per-handler execution limits with sliding window.
- Recurring jobs. Interval-based and cron-based scheduling with configurable overlap policies (Allow, Skip, Buffer).
- Workflow cancellation. Cancel running workflows and trigger registered cleanup handlers.
- State pruning. Automatically remove old step outputs to keep large workflow state manageable.
- Worker concurrency.
--workers=Nforks multiple processes with automatic restart on crash. - Full observability. Database logging, per-handler metrics, and event webhooks.
- Testing utilities.
QueueFakerecords dispatched jobs and batches for assertions in unit tests. - PHP attributes.
#[QueuetyHandler('name')]for zero-config handler registration.
How it works
Workers boot from a minimal bootstrap that parses wp-config.php via regex (not require) to extract database credentials, then connects directly via PDO. No plugins, themes, or hooks are loaded. For handlers that need WordPress (like wp_mail), Queuety can optionally boot it per-handler.
Workflows break long-running work into steps. Each step persists its output to a shared state bag in the database. If PHP dies mid-step, the worker retries that step with all prior state intact. The step boundary is a single MySQL transaction: state update, job completion, and next step enqueue all happen atomically.
Workflow: generate_report (3 steps)
Step 0: fetch_data -> state: {user_data: {...}}
Step 1: call_llm -> PHP dies -> retry -> state: {user_data: {...}, llm_response: "..."}
Step 2: format_output -> state: {user_data: {...}, llm_response: "...", report_url: "/reports/42.pdf"}
Workflow: completedRequirements
- PHP 8.2 or later
- WordPress 6.4 or later
- MySQL 5.7+ or MariaDB 10.3+