Skip to content

Async actions: tries(), backoff(), asUser(), onQueue() - #10

Merged
ogorzalka merged 1 commit into
mainfrom
feat/async-retries
Oct 7, 2026
Merged

ogorzalka merged 1 commit into
mainfrom
feat/async-retries

Conversation

@ogorzalka

Copy link
Copy Markdown
Member

Phase 2, step B: retries, original user, queue name.

tries() and backoff()

Action::add('woocommerce_order_status_completed', [OrderExporter::class, 'export'])
    ->async()->tries(3)->backoff([30, 300]);
  • A handler that throws is queued again through the driver that queued it (recorded in the payload), with attempt + 1, after the delay for that attempt.
  • Each failed attempt is reported (Attempt 1 of 3 failed, retried in 10 s: …). The last failure is reported and fired as pollora/async/failed, as before.
  • backoff() default is [10, 60, 300], the values planned for the framework's config/hooks.php; the last value repeats. Invalid values (tries(0), empty or negative backoff) throw InvalidArgumentException at registration.
  • Not retried: a handler that no longer exists, or an unreadable payload (retrying cannot help), and a deleted referenced object (dropped, as before).
  • If the retry itself cannot be queued (driver unavailable), both incidents are reported and the failure is final.
  • WP-Cron: the retry reuses the payload ID. The option was claimed (deleted) when the run started, so it is stored again, under a new event.
  • sync: retries happen at once, nested.

asUser()

Runs the handler as the user who fired the hook, then switches back to the previous user, always in a finally. Order: site, then user (capabilities depend on the site), then locale; restored in reverse. Without it, the handler runs with no current user, the safe default; the ID stays readable in the context. Nothing is switched when nobody was logged in.

onQueue()

Records the queue name in the payload: the group for Action Scheduler (next PRs) and the queue for the framework's Laravel driver. WP-Cron ignores it.

Payload

New fields driver, queue, asUser, backoff. Optional on read, so payloads queued by 1.2.0 still run (tested). backoff is validated when read back.

Tests

183 passed, 19 new. The real-WordPress suite still passes. PHPStan level 5 and Pint pass.

@ogorzalka
ogorzalka merged commit efbf941 into main Oct 7, 2026
5 checks passed
@ogorzalka
ogorzalka deleted the feat/async-retries branch October 7, 2026 13:06
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