Acorn queues
Background job processing in WordPress via Acorn: Laravel queue, dispatch, queue:work, ShouldQueue, failed jobs, Action Scheduler, as_schedule_single_action, as_schedule_recurring_action, job retries, backoff, job chaining, job batching, ShouldBeUnique, Acorn queue, Redis queue driver, database queue driver, queue worker, background tasks — using Acorn's Laravel queue stack in Sage/WordPressFrom its SKILL.md
npx -y skills add hekivo/superpowers-sage --skill acorn-queuesAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 13 stars13 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
8.0 KB, as published. Nobody here has run it
Queues, Jobs, and Background Tasks
When to Use What
| Criteria | Action Scheduler | Laravel Queue + Job |
|---|---|---|
| Best for | Simple recurring tasks, WP-native workflows | Robust async, retry logic, heavy computation |
| Infrastructure | None — runs on WP cron | Needs queue driver (database or Redis) |
| Retry/backoff | Manual | Built-in ($tries, $backoff, exponential) |
| Monitoring | WP Admin > Tools > Scheduled Actions | lando acorn queue:failed, logs |
| Examples | Daily cleanups, content sync, email digests | Image processing, API syncs, bulk imports |
| Already available | Bundled with WooCommerce; standalone via woocommerce/action-scheduler | Requires Acorn queue config + worker |
Rule of thumb: Start with Action Scheduler for simple recurring WordPress tasks. Move to Laravel Queue + Job when you need retries, backoff, chaining, batching, or processing that could take more than a few seconds.
Quick Start — Laravel Queue
# 1. Create a job class
bash skills/acorn-queues/scripts/create-job.sh ProcessImage
# 2. Create queue tables (database driver)
lando acorn queue:table
lando acorn queue:failed-table
lando acorn migrate
# 3. Set driver in .env
# QUEUE_CONNECTION=database
# 4. Start a worker
bash skills/acorn-queues/scripts/run-worker.sh
bash skills/acorn-queues/scripts/run-worker.sh emails
Quick Start — Action Scheduler
# Install (if not using WooCommerce)
lando composer require woocommerce/action-scheduler
// Schedule once
as_schedule_single_action(strtotime('+10 minutes'), 'app/sync_content', ['post_id' => 42], 'content-sync');
// Schedule recurring (guard against duplicates)
if (! as_has_scheduled_action('app/cleanup_tokens', [], 'maintenance')) {
as_schedule_recurring_action(time(), HOUR_IN_SECONDS, 'app/cleanup_tokens', [], 'maintenance');
}
Register callbacks in ThemeServiceProvider::boot():
add_action('app/sync_content', function (int $postId): void {
$this->app->make(\App\Services\ContentSyncService::class)->syncPost($postId);
});
Job Class Anatomy
class ProcessImage implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public int $tries = 3;
public array $backoff = [10, 60, 300]; // exponential: 10s, 1min, 5min
public function __construct(protected readonly int $attachmentId) {}
public function handle(): void
{
// If job needs WP user context:
// wp_set_current_user($this->userId);
$file = get_attached_file($this->attachmentId);
if (! $file || ! file_exists($file)) {
return; // idempotent exit — attachment gone
}
// ... process
}
public function failed(?\Throwable $exception): void
{
Log::error('ProcessImage permanently failed', ['attachment_id' => $this->attachmentId]);
}
}
Dispatching Jobs
// Basic
ProcessImage::dispatch(attachmentId: $id);
// Delayed (5 minutes)
SyncContent::dispatch(sourceId: $id)->delay(now()->addMinutes(5));
// Specific queue
SendEmail::dispatch(campaignId: $id)->onQueue('emails');
// From a WordPress hook
add_action('add_attachment', function (int $id): void {
if (wp_attachment_is_image($id)) {
ProcessImage::dispatch(attachmentId: $id);
}
});
Scripts
# Create a job class (validates PascalCase, checks lando on PATH)
bash skills/acorn-queues/scripts/create-job.sh <JobName>
# Run a queue worker (default queue, 3 tries, 60s backoff)
bash skills/acorn-queues/scripts/run-worker.sh
bash skills/acorn-queues/scripts/run-worker.sh emails
Script source: scripts/create-job.sh · scripts/run-worker.sh
Assets
Boilerplate templates with {{CLASS_NAME}} placeholder. Copy and replace.
- job-simple.php.tpl — Simple job with
handle()+failed(),$tries,$backoff,wp_set_current_userstub. - job-batched.php.tpl — Batched job with
use Batchable,$this->batch()->cancelled()check.
References
Deep content loaded on demand — zero tokens until needed.
- action-scheduler.md — Action Scheduler setup,
as_schedule_single_action,as_schedule_recurring_action, callbacks, duplicate-schedule prevention, cron-based queue trigger. - laravel-queue.md — Full
config/queue.php, all drivers, database setup, dispatching patterns, job chaining, batching, testing withBus::fake(). - redis-driver.md — Redis-backed queue, Lando Redis service config (
REDIS_HOST=cache), queue isolation, failover to database driver, Supervisor config. - job-patterns.md — Idempotency patterns, chunking large datasets, retry/backoff config,
ShouldBeUnique+uniqueId(),wp_set_current_userin jobs, pass IDs not objects. - troubleshooting.md — Failed jobs table,
queue:workdebug flags, common errors (jobs stuck, Redis refused, class not found, memory exhaustion), escalation paths.
Verification
- Dispatch a test job and confirm it appears in the queue: check the
jobstable (database driver) orlando redis-cli -h cache LLEN queues:default(Redis driver). - Run
lando acorn queue:work --onceand confirm the job processes successfully with expected log output. - After processing, verify the job is removed from the queue and does not appear in
lando acorn queue:failed.
Failure modes
Problem: Jobs dispatched but never processed
- Cause: No worker is running, or
QUEUE_CONNECTIONin.envdoes not match a connection inconfig/queue.php. - Fix: Start a worker (
bash skills/acorn-queues/scripts/run-worker.sh). VerifyQUEUE_CONNECTIONmatches a valid connection key. For the database driver, runlando acorn queue:table && lando acorn migrate.
Problem: Jobs fail and the failed_jobs table does not exist
- Cause: The failed jobs migration was never run.
- Fix:
lando acorn queue:failed-table && lando acorn migrate. Then retry withlando acorn queue:retry all.
For all other failure modes see references/troubleshooting.md.
Critical Rules
- Action Scheduler vs Laravel Queue: Use Action Scheduler for simple recurring WP-native tasks. Use Laravel Queue + Job when you need retries, backoff, chaining, batching, or heavy computation.
wp_set_current_userin jobs: If a job callscurrent_user_can()or any WP function that relies on the current user, callwp_set_current_user($userId)at the top ofhandle(). Jobs run outside the HTTP lifecycle — WP does not set a current user automatically.- Idempotency: Every job must be safe to run more than once. Use guard clauses or upsert patterns. See
references/job-patterns.md. - Pass IDs, not objects: Pass
$postIdinstead of$post. Re-fetch inhandle()to avoid serialization issues and stale data on retry. - Set
$triesand$backoff: Never let jobs retry infinitely. Use exponential backoff arrays for external API jobs. - Failed jobs table must exist: Run
lando acorn queue:failed-table && lando acorn migratebefore running workers in production. syncdriver is for development only. It blocks the HTTP request and runs jobs inline. SetQUEUE_CONNECTION=databaseorredisin production.- Redis host inside Lando is the service name (
cache), not127.0.0.1. Seereferences/redis-driver.md.