Async Dispatch Retries
6 min read
- View as Markdown Open this page as plain Markdown (opens in a new tab)
- Open in ChatGPT Ask questions about this page (opens in a new tab)
- Open in Claude Ask questions about this page (opens in a new tab)
- Open in Google AI Studio Ask questions about this page (Google account required) (opens in a new tab)
The automation engine runs most rule actions immediately, in the request that fired the trigger. The exception is Send Webhook: webhook deliveries are dispatched asynchronously through Action Scheduler with automatic retry on failure. This page covers the dispatch model, the retry policy, what happens when a delivery fails permanently, and how to monitor dispatcher health.
The Dispatch Model #
When a rule fires:
- The engine evaluates conditions in-process (fast, blocking)
- If conditions pass, the action runs straight away — Block Customer, Allowlist Customer, Flag for Review, Add Tag, Remove Tag, Add Admin Note, Send Email Notification, Hold Order, Cancel Order and Require Verification all finish inside the triggering request and are logged OK or ERR
- Send Webhook instead becomes a queued Action Scheduler job (hook
trustlens/automation/dispatch_webhook, grouptrustlens-automation) and is logged as QUEUED - The triggering event proceeds normally — no waiting for the webhook
- Action Scheduler picks up the job on its next run (usually within a minute)
- The job POSTs the payload; a 2xx is logged as OK
- A failed delivery is rescheduled per the retry policy
This separation means: a customer’s checkout completes immediately even if a downstream webhook receiver is slow. The inline actions are quick database and order-status updates; Send Email takes as long as your mail setup.
From 1.3.23 there is one more delayed case: Hold Order, Cancel Order and Require Verification on an order that isn’t paid yet (an Order Placed rule) are logged as QUEUED and applied when the payment is confirmed. That waits on the order’s status, not on Action Scheduler. See Actions Reference.
If Action Scheduler isn’t available at all, webhooks are sent inline once, without retries.
The Retry Policy #
| Attempt | Delay From Original Trigger |
|---|---|
| 1 (initial) | Immediate (on Action Scheduler’s next run) |
| 2 (retry 1) | + 60 seconds |
| 3 (retry 2) | + 120 seconds (180s from original) |
| 4 (retry 3) | + 240 seconds (420s from original) |
| Stop | After 4 total attempts, the delivery is marked failed |
Each delay is counted from the failed attempt, so a timeout (up to 10s) and Action Scheduler’s run interval add to these figures. The backoff is exponential (60 → 120 → 240). This catches most transient failures — a receiver that’s down for a couple of minutes will usually be back before the last retry.
What Counts as a Failure #
| Action | Failure Conditions |
|---|---|
| Send Webhook | Any non-2xx response (including 3xx — redirects aren’t followed), timeout (10s), DNS failure, connection refused. Retried as above |
| Hold / Cancel order, Require Verification | An error thrown while changing the order, or no order in scope. Logged as ERR, not retried |
| Block / Allowlist / Tag / Note / Flag | Database or other errors thrown while running (very rare). Logged as ERR, not retried |
| Send Email Notification | Not detected — a wp_mail() failure isn’t logged as an error |
Non-2xx HTTP responses are treated as failure. A 200 with an error body is treated as success — TrustLens only checks the status code.
Permanent Failure #
After 4 total attempts (initial + 3 retries), the webhook delivery is marked failed and stops retrying. The failure is recorded in the automation log with the final attempt’s error, e.g. “Webhook returned HTTP 503 after 4 attempt(s).” Intermediate failed attempts aren’t logged separately.
Permanent failures don’t automatically alert — there’s no failure notification setting. To catch them:
- Check the error count on the Automation page header (“errors today”) and each rule’s Errors stat
- Review the Rule Inspector of webhook rules weekly
- Monitor your receiver for missing deliveries
Action Scheduler Health #
Webhook dispatch depends on Action Scheduler (bundled with WooCommerce) running its scheduled actions reliably. If Action Scheduler stalls:
- Queued deliveries sit in the queue but never execute
- Retries never happen
- The Rule Inspector shows QUEUED rows that never get an OK or ERR follow-up
To check Action Scheduler health: WooCommerce → Status → Scheduled Actions. Filter by status:
- Pending — waiting to run; should drain within minutes on a healthy site
- In progress — actively executing; should clear quickly
- Complete — finished (a delivery that got a non-2xx and scheduled its own retry also shows as complete)
- Failed — exception thrown during execution
If pending count is climbing without draining, WP-Cron is probably disabled or your host is rate-limiting. Set up a real cron job hitting wp-cron.php every minute.
Deduplication #
The dispatcher deduplicates webhook jobs at queue time. If the same rule queues a delivery for the same customer while an identical one is still pending, the two collapse into a single delivery. Retries carry their attempt number, so they’re never collapsed into the original.
Different rules never collapse into each other — each rule queues its own delivery.
Cooldowns vs Retries #
Two related but distinct concepts:
- Cooldown — minimum time between firings of a rule for the same customer. Fixed at one hour for customer-level actions (Send Webhook included); order actions have none. There’s no per-rule setting; developers can change it with the
trustlens/automation/rule_cooldownfilter. - Retry — automatic re-attempt of a failed webhook delivery. Set at the engine level (60/120/240). Not configurable per rule.
A Send Webhook rule queues at most one delivery per customer per hour, and each delivery is retried up to 3 times. The two behaviors are independent.
Webhook-Specific Retry Behavior #
For webhook actions, retry is driven by the HTTP status only:
- 5xx responses: retry (server probably temporary issue)
- 4xx responses: retry (might be a transient routing issue)
- 3xx responses: retry — redirects aren’t followed, so fix the URL
- Timeouts: retry
- 2xx response: success, no retry
Some webhook receivers signal “don’t retry” with specific status codes (some APIs use 410 Gone). TrustLens doesn’t special-case any 4xx — all retry the same way. If you have a receiver that genuinely shouldn’t retry, return 2xx and ignore the payload instead of erroring.
Monitoring Dispatch Health #
Periodically check:
- Action Scheduler queue depth — anything chronically large indicates the dispatcher is falling behind
- Rule error counts — climbing errors suggest an upstream issue (slow webhook receiver, wrong URL)
- Average execution time — shown per rule in the Rule Inspector’s 7-day panel; should be sub-second for most actions
If you’re running 100+ rule fires per day, build a habit of reviewing dispatch health weekly. It’s the kind of system that’s silent when working correctly and silent when broken — the failure mode is usually “nothing is happening anymore.”
Synchronous Execution #
Every action except Send Webhook already runs synchronously, so a rule on Order Placed acts during checkout. Webhooks can’t be made synchronous (unless Action Scheduler is missing). If you need an external call to finish before WooCommerce continues, write a custom WooCommerce action hook handler directly.
The trade-off: async webhook dispatch is much safer (no risk of slowing checkout, no risk of taking down the site if a receiver is slow) but means webhook receivers are eventually consistent, not immediately consistent.
Updated on October 18, 2026