Skip to content

My Automation Isn't Triggering — How to Diagnose from the UI

A welcome series or drip that won't fire on new subscribers. The Automations dashboard shows you whether the workflow is active, what trigger it's listening for, and which subscribers are eligible — three checks resolve most cases.

What to check from the dashboard

Automations that "don't fire" almost always have a UI-visible reason — wrong status, wrong trigger, or the subscriber doesn't match the condition the workflow is waiting for. Walk these three checks before logging into the server.

Open Automations in the left sidebar:

Automations index — status badges visible

Find your workflow row. Three columns matter:

  1. StatusActive means it will trigger; Inactive, Draft, or Paused will NOT.
  2. Last run — when did a subscriber last enter this workflow?
  3. Subscribers in flow — current count of recipients somewhere in the steps.

If status is anything but Active, that's your fix. Click the row → Settings → toggle Active. Save.

Check the trigger node

If status is Active but new subscribers still aren't entering, click the workflow name to open the flow canvas:

Automation flow canvas — trigger + steps

The first node is the trigger. Common misconfigurations:

Trigger type What it listens for Common pitfall
Subscribed to list New rows in a specific mailing list Wrong list selected — workflow fires on List A but subscribers are being added to List B
Tag added A specific tag attached to a subscriber Tag name typo / case mismatch — vip vs VIP are different
Custom event (API) Your application calls POST /api/automations/{uid}/event API call missing or hitting wrong workflow uid
Date relative A specific date field (birthday, signup_date) matches today Field empty for most subscribers — workflow only fires for the few with that field populated
Link clicked Subscriber clicks a specific link in a campaign Link not yet clicked by anyone — wait for engagement

Hover over the trigger node — the right-hand panel shows the exact configuration. Verify it matches your list, tag, or event name.

Verify the workflow settings

Click Settings in the top-right of the flow canvas:

Automation settings — eligibility + cooldown

Three settings commonly block firing:

  • Allow re-entry? — If OFF, a subscriber who entered once (even years ago) can't re-enter. Toggle ON if you want every signup to flow through.
  • Cooldown period — A subscriber who entered N hours/days ago can't re-enter until cooldown expires.
  • Eligibility filter — Optional segment/tag filter. Subscribers who don't match the filter skip the workflow entirely.

Common UI causes and the fix from the dashboard

What you see Likely cause What to do
Status: Inactive Workflow toggled off (common after edits — AcelleMail un-activates on save). Open Settings → toggle Active → Save.
Trigger = Subscribed to list, wrong list Workflow listens on List A but new signups go to List B. Edit trigger → pick correct list → Save.
Trigger = Tag added, no recent tagging Tag never added to any subscriber. Either tag a subscriber to test, or change the trigger to a more reachable condition.
Trigger = Date relative, empty fields Most subscribers don't have the date field populated. Import the field via CSV update, or change to a different trigger.
Status: Active but Subscribers in flow = 0 Trigger fires correctly but the first delay node hasn't elapsed yet. Wait for the delay duration, then refresh.
Status: Active, Subscribers in flow > 0, no emails sent Send-step is failing (sending server issue). Check Settings → Sending servers → run Test connection. See Campaign stuck in Sending.

Test the workflow by hand

The fastest way to confirm "is this workflow actually firing?" is to manually trigger it:

  1. Create a test subscriber with an address you control (your own email).
  2. Add that subscriber to the list / apply the tag / fire the API event — whatever the trigger expects.
  3. Wait the configured delay (start with workflows that have <5 min first-step delay for fast iteration).
  4. Check your inbox.

If the test subscriber receives the email → workflow is fine, your original signups aren't matching the trigger (back to dashboard checks).

If the test subscriber does NOT receive → either the workflow isn't firing, or the send is failing. See operator section.

Advanced: server-side checks for the operator

AcelleMail automations run on the same queue worker that processes campaigns. If campaigns are sending but automations aren't, the worker is processing the wrong queue mix.

Queue priorities — automation jobs go onto the automation queue by default. Verify the worker is listening to it:

ps aux | grep "queue:work" | grep -v grep
# Expected: includes --queue=high,default,low,automation

If automation is missing from the worker's --queue flag, restart Supervisor with the correct config:

sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl restart acelle-queue-worker:*

Cron and the master scheduleracelle:run ticks every minute and picks up time-based automation triggers (date-relative, delayed step transitions). If cron is broken, time-driven steps stall while immediate triggers (subscribe / tag / API event) still work.

crontab -l | grep acelle:run
# Expected: * * * * * php /path/to/artisan acelle:run >/dev/null 2>&1

Inspect a specific automation's history via the database — every entry/exit is logged:

# Recent automation runs
php artisan tinker --execute='
  \App\Model\AutomationCustomerInteraction::orderByDesc("id")
    ->limit(20)->get()
    ->each(fn($r) => print("uid={$r->automation_uid} sub={$r->subscriber_uid} step={$r->step_uid} at={$r->created_at}\n"));
'

Failed-job inspection — if a step throws an exception, the job goes to failed_jobs. Look for entries with Automation in the payload:

php artisan queue:failed
php artisan queue:retry all  # retry every failed job

Workflow-uid → log mapping — to find why a SPECIFIC subscriber didn't enter:

grep "subscriber_uid=<uid>" storage/logs/laravel.log | tail -20

Related articles

25 comments

18 comments

  1. Daniel
    cause #2 (dead supervisor) hit us after a kernel-upgrade reboot. The systemctl enable bit was missing. Took 2 hours to figure out because nothing was logging...
  2. Brian
    we hit cause #5 last quarter — ses sandbox limits we didn't know about. the 'wait it out' advice is right. we tried aggressive retries first and it just made things worse.
  3. Joel
    adding to this: we had a campaign stuck for 6 hours one time. Turned out the running_pid was alive but the worker was deadlocked on a slow MySQL query. ps showed it as running, kill -9 was the only fix. Now we monitor for stale running_pid > 30 min.
    1. Admin
      A live PID is the weakest of the checks, it only tells you the process exists, not that it's making progress. That's why the UI can show a campaign as running forever while the worker sits on a lock. The better signal is the activity timestamp rather than the PID. If it hasn't moved in 30 minutes but the PID is alive, something is blocked, and long MySQL queries are the usual suspect. Check SHOW PROCESSLIST before you kill, you'll usually find the query and the reason it's slow (missing index on a large subscribers table, most times). I'll add a section on stale-but-alive workers to this article, since the current diagnosis steps assume a dead process. Your 30 minute threshold is a sensible default.
  4. Sarah
    Sent this to my whole ops team. Should be required reading before anyone touches the prod queue.
  5. Aditi
    I think the recommendation to wait 10-15 minutes is too patient for production. We alert at 5 minutes and our ops team triages. Stuck status > 5 min usually means something real.
    1. Admin
      The 10-15 minutes in the article is deliberately conservative because it has to cover people whose queue worker died and who won't know that for a while. If you're watching the queue and your ops team triages, 5 minutes is the right call. Stuck longer than one worker cycle plus a bit of slack is already a signal. I'll rework that section to give two thresholds instead of one number, with the reasoning attached, so people can pick based on whether anyone is actually on call.
  6. Akira
    When you say to bump wait_timeout to 86400, does that need a MySQL restart or is it dynamic? We're on RDS so restarts are expensive
    1. Admin
      Dynamic, no reboot. Set it in a custom parameter group (you can't edit the default one). Only new connections pick it up, so restart queue:work after.
  7. Aisha
    Pro-tip: set `pm.max_children` on your PHP-FPM pool to at least 2x your supervisor worker count. Otherwise even ack-fast endpoints choke when the queue rate goes up. tbh
  8. James
    Thanks for grounding this in actual source — much better than the generic Laravel advice you find on Stack Overflow.
  9. Ahmed
    curious if the 200-row / 32-advance bounds are configurable. We have one customer with very large automation flows and I wonder if they hit this.
    1. Admin
      Not configurable today. Both bounds are constants in the automation runtime, not settings or env vars, so there's no knob to turn without patching. They're per-execution-pass limits though, not per-flow caps: a flow that needs more than 32 advances just picks up where it left off on the next tick rather than failing. So a large flow gets slower, not stuck. The one case worth watching is if your customer's flow is wide enough that a full pass never drains between ticks and the queue backs up. If you see that, send me the automation ID and the tick interval you're running and I'll look at whether the constants should become config. Nobody has hit the ceiling hard enough to justify it yet, but that's a reason not a principle.
  10. Marcus
    For anyone running on EC2 t3.small — bump to t3.medium before you scale past 50k subs. We learned the hard way that worker OOM kills explode when MySQL is on the same instance
  11. Minh
    what about the case where campaign:rerun itself crashes silently? We had cron running but :rerun was failing on a deleted customer and just bailing out. No alerts
    1. Admin
      That's a real gap. A crash inside the rerun loop kills the whole pass, so every other automation stops too and the UI shows nothing except triggers that quietly stop advancing. The article only covers the "cron isn't running at all" case, which looks identical from the dashboard. Two things worth doing on your side now: pipe the cron output somewhere instead of /dev/null (a MAILTO or redirect to a log file), and check the log around the time the automations went quiet. An orphaned automation whose customer is gone will usually show up as a null dereference in that trace. On our side the loop should be per-automation try/catch so one bad row doesn't take the pass down, and orphans should be skipped and flagged rather than exploding. I'll add a diagnostic step to the article for reading the cron output, since right now it just assumes cron either works or doesn't.
  12. Tomas
    is there a way to detect cause #6 (lost db connection) before workers wedge? looking for a heartbeat metric to alert on.
    1. Admin
      No heartbeat metric exists yet. Alert on the age of the oldest unreserved job instead, it climbs while depth stays flat. Also run workers with --max-time so they recycle the connection.
  13. Anna
    This article saved me about 4 hours of debugging today. The diagnostic order at the top is exactly the workflow I needed.
  14. Quân
    Bookmarking this. Wish I had it last month when our queue backed up on a Sunday night
  15. Carlos
    If you're on Ubuntu 22.04 with the default cron package, the time zone is UTC even if /etc/timezone says otherwise. Bit us once — the scheduled job timing was 7 hours off.
  16. Emma
    question: in step 4, the campaign log line about 'force resuming' — does that show up in laravel.log or only the per-campaign log file? our laravel.log seems silent on this.
    1. Admin
      Per-campaign file, not laravel.log. The campaign runner writes its own log per campaign under storage/logs, and laravel.log only picks things up when something actually throws or a queue job fails. So a silent laravel.log while the campaign is force resuming is expected, not a sign the step didn't run. If you can't find the per-campaign file, tail the storage/logs directory while you trigger the automation and see which file grows. That's the one step 4 means. I'll make the article say which log explicitly, right now it just says "the campaign log" and clearly that reads ambiguous.
  17. Ravi
    One more thing worth adding: if you use Cloudflare in front, make sure to whitelist the worker IPs for outbound — we had retries failing because Cloudflare was rate-limiting our own outbound traffic to SES.
  18. Chen
    Confirming the campaign:rerun auto-fix actually works. We had a worker OOM mid-batch last week, walked away thinking wed need to manually intervene, came back in 15 minutes and it had recovered itself.

More in Troubleshooting