From superpowers-sage
Provides guidance on background job processing in WordPress Sage using Acorn's Laravel queues: dispatch, workers, retries, backoff, chaining, batching, failed jobs, and Action Scheduler alternatives.
npx claudepluginhub codigodoleo/superpowers-sage --plugin superpowers-sageThis skill uses the workspace's default tool permissions.
| Criteria | Action Scheduler | Laravel Queue + Job |
Provides Laravel queue best practices: job structure, dispatch patterns, middleware, chaining, batching, retries, and error handling. Useful for reliable async task processing.
Implements background job processing with task queues, workers, scheduling, retries, and monitoring. For async long-running tasks, emails, reports, large datasets.
Configures and reviews Rails background jobs using Active Job with idempotency checks, retry/discard strategies, Solid Queue (Rails 8+) or Sidekiq, and recurring jobs via recurring.yml or sidekiq-cron.
Share bugs, ideas, or general feedback.
| 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.
# 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
# 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);
});
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]);
}
}
// 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);
}
});
# 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
Boilerplate templates with {{CLASS_NAME}} placeholder. Copy and replace.
handle() + failed(), $tries, $backoff, wp_set_current_user stub.use Batchable, $this->batch()->cancelled() check.Deep content loaded on demand — zero tokens until needed.
as_schedule_single_action, as_schedule_recurring_action, callbacks, duplicate-schedule prevention, cron-based queue trigger.config/queue.php, all drivers, database setup, dispatching patterns, job chaining, batching, testing with Bus::fake().REDIS_HOST=cache), queue isolation, failover to database driver, Supervisor config.ShouldBeUnique + uniqueId(), wp_set_current_user in jobs, pass IDs not objects.queue:work debug flags, common errors (jobs stuck, Redis refused, class not found, memory exhaustion), escalation paths.jobs table (database driver) or lando redis-cli -h cache LLEN queues:default (Redis driver).lando acorn queue:work --once and confirm the job processes successfully with expected log output.lando acorn queue:failed.QUEUE_CONNECTION in .env does not match a connection in config/queue.php.bash skills/acorn-queues/scripts/run-worker.sh). Verify QUEUE_CONNECTION matches a valid connection key. For the database driver, run lando acorn queue:table && lando acorn migrate.failed_jobs table does not existlando acorn queue:failed-table && lando acorn migrate. Then retry with lando acorn queue:retry all.For all other failure modes see references/troubleshooting.md.
wp_set_current_user in jobs: If a job calls current_user_can() or any WP function that relies on the current user, call wp_set_current_user($userId) at the top of handle(). Jobs run outside the HTTP lifecycle — WP does not set a current user automatically.references/job-patterns.md.$postId instead of $post. Re-fetch in handle() to avoid serialization issues and stale data on retry.$tries and $backoff: Never let jobs retry infinitely. Use exponential backoff arrays for external API jobs.lando acorn queue:failed-table && lando acorn migrate before running workers in production.sync driver is for development only. It blocks the HTTP request and runs jobs inline. Set QUEUE_CONNECTION=database or redis in production.cache), not 127.0.0.1. See references/redis-driver.md.