Stop Running AI Agents Naked on Cron: 8 Iron Rules for Reliability

Treat AI Agents as ordinary background jobs: cron enqueues only, idempotency, layered retries, dead letter and heartbeat both essential.
The article argues for stopping treating AI Agents as magical reasoning machines and engineering them as ordinary background jobs. The core principle is that cron only creates tasks and doesn't execute Agent logic directly, persisting through queues consumed by workers. Duplicate triggers should be handled as an idempotency problem with business-derived keys and dedicated idempotency tables. Retries belong inside worker execution steps with exponential backoff, where model calls and external APIs live. Choose the tool your team can operate correctly at 2 AM. Dead letter queues isolate permanent failures, and heartbeat monitoring catches silent stops. Model failover should be an explicit timeout and fallback policy. Conclusion: first make the Agent boring, then make it smart.
Stop Running AI Agents Naked on Cron: 8 Iron Rules for Reliability

Running an AI Agent directly on cron is like putting a smart but forgetful employee on the night shift alone—nothing goes wrong most of the time, but when it does, it's a big deal. I've seen too many teams spend their energy comparing whether GPT-5 or Claude is smarter, while letting unattended tasks run on luck. What really keeps an Agent alive isn't a stronger model, but treating it like a boring background job.
The original author puts it bluntly: the biggest improvement he ever made had nothing to do with prompts—it was stopping treating the Agent as a magical reasoning machine and starting to treat it as an ordinary background job. This mindset shift fixed more production issues than any model upgrade.
One-Sentence Architecture: Cron Creates Work, It Doesn't Do Work
The core principle is just one: Cron should create work, not do work.
The standard pattern is—cron, GitHub Actions, webhooks, or n8n timers only drop tasks into a queue; the queue persists storage; workers execute the Agent steps; monitoring verifies the trigger actually happened; failed tasks either retry or go to the dead letter queue.
Not sexy, but extremely effective. If you've ever experienced the same task still running while the next one starts, or a machine restarting at exactly the wrong time, you understand why "scheduling is a request, not a guarantee."
The bad pattern is letting cron run the full Agent logic directly: */15 * * * * node run-agent.js. The good pattern is enqueue-only: */15 * * * * node enqueue-agent-job.js, with the script writing to BullMQ, SQS, or Cloudflare Queues. If you use n8n, queue mode itself pushes you in this direction—the main process handles timers and webhooks while workers execute tasks separately, far more reliable than those single-process demo workflows.
Rules 1-2: Enqueue and Idempotency, Don't Blame the LLM
Duplicate Triggers Are an Idempotency Problem, Not an AI Problem
When the same task triggers twice, many people's first instinct is to add AI logic to judge. Don't do that. Duplicate suppression isn't something GPT-5 should solve—it's an idempotency problem.
The cleanest fix is a business-derived key, like customer-123-daily-summary-2026-10-17, account-42-invoice-followup-2026-10-17, ticket-9981-first-response. This key represents a business event you want to happen only once.
BullMQ allows you to pass a jobId when calling queue.add, and identical IDs are ignored while the old job still exists. But there's a catch: deduplication only works while the old job is still there. If you aggressively clean up completed or failed tasks, the deduplication window disappears with them.
| Approach | What You Gain | What You Lose |
|---|---|---|
| Keep more completed/failed jobs | Longer deduplication window | More Redis storage pressure |
| Aggressive auto-cleanup | Lower storage cost | Weaker idempotency when relying on queue history |
| Dedicated idempotency store | Strong duplicate protection | More moving parts |
The author's judgment: if side effects matter, use a dedicated idempotency record. Sending emails, charging cards, creating Zendesk tickets, posting Discord messages, writing to CRM—these all deserve an agent_idempotency table, using insert ... on conflict do nothing to determine whether it's already been processed. Queue history is useful, but it shouldn't be your only memory.
Idempotency is defined as: the side effects on system state from executing the same operation once versus multiple times are exactly the same. In distributed systems, due to network timeouts, retries, scheduler jitter, and other reasons, "at least once" delivery is almost the norm, so idempotency is a fundamental means of ensuring correctness. There are three common implementation paths: database unique constraints (like insert ... on conflict do nothing), business-derived deduplication keys, and external idempotency services (like idempotency tokens in payment scenarios). It's important to distinguish that idempotency is not fully equivalent to "deduplication": deduplication focuses on "not processing twice," while idempotency focuses on "processing twice doesn't break state." For irreversible side effects like sending emails or charging cards, relying solely on a deduplication window is unreliable—you must land on a dedicated idempotency record to keep working across boundaries like queue cleanup and process restarts.
Rules 3-4: Retry at the Right Layer, Choose a Queue You Can Operate
Retry Model Calls Inside Worker Steps
Retrying is good, but retrying at the wrong layer is a disaster. The author's recommended division of labor: the orchestration layer decides what to do next, worker steps do non-deterministic work, LLM calls and API calls happen inside retryable execution steps, and side effects only happen after idempotency checks.
This means GPT-5, Claude Opus 4.6, Grok 4.20, OpenAI-compatible endpoints, CRM APIs, webhooks—all live in the worker layer, not in some "Agent brain."
Exponential backoff is more important than many people realize. BullMQ's exponential backoff formula is 2 ^ (attempts - 1) * delay. With a base delay of 3000ms, the 7th attempt waits 192 seconds, about 3.2 minutes. When OpenAI, Anthropic, or your CRM is having a bad hour, you want retries stretched to real time scales, not hammering the vendor every few seconds.
By the way, if your Agent is retrying, fanning out, summarizing, classifying, and recovering all day, token-based billing turns reliability work into a budget problem. This is exactly why flat-rate OpenAI-compatible infrastructure is attractive for Agent-intensive systems—you can build for robustness without staring at token bills every time the workflow runs a few more times.
Choose the Queue You Can Get Right at 2 AM
People love to ask which queue or orchestration tool is best. The real question is usually: which one can your team still operate correctly at 2 AM?
| Tool | Use Case |
|---|---|
| BullMQ | Node.js workers needing custom job IDs, retries, and Redis persistence |
| Temporal | Multi-step Agents where deterministic orchestration and activity-level retries really matter |
| n8n queue mode | 7×24 automation starting from n8n but needing real worker separation |
| AWS SQS | Wanting AWS-native managed queues |
| Cloudflare Queues | Managed queues, batching, and edge-friendly architecture |
For simple Agents, BullMQ + Redis + Healthchecks.io is often enough. If the Agent has long waits, branching logic, approvals, and multiple external systems, Temporal goes from over-engineering to basic self-respect.
Temporal is a durable execution platform at a different level of abstraction from task queues like BullMQ. BullMQ manages "jobs," with retries at the whole-job level; Temporal manages "workflows," where the workflow code itself is persisted, each activity (external call, LLM call) has its own timeout, retries, and state records, and after a process crash it can resume from the breakpoint rather than rerunning from scratch. This makes it naturally suited for Agent orchestration with long waits, human approvals, multiple branches, and multiple external systems. The cost is more concepts (workflow, activity, task queue, determinism constraints) and significantly higher operational complexity and learning curve than Redis queues. So the criterion isn't "who's stronger," but whether the team has the ability to locate workflow state during failures—which is exactly what "getting it right at 2 AM" actually means.
Rules 5-6: Dead Letter Queue and Heartbeat Monitoring—Both Are Essential
Dead Letter Queue Is Not Optional
As long as your Agent touches real traffic, it needs a place to put poison tasks—not later, now. Because some failures are temporary (rate limiting, 502, model timeout, transient network issues) and some are permanent (malformed payload, deleted account, impossible state, missing required fields). They shouldn't spin forever in the same retry loop.
A dead letter payload should at minimum contain: original input, error category, stack trace or failure reason, attempt count, timestamp, source queue name. The author's dead letter rules are clear: retry network and model failures, fast-track malformed input to the dead letter queue, the DLQ must be visible on dashboards, and prioritize manual reprocessing before considering automated reprocessing.
If the dead letter queue becomes a graveyard nobody looks at, what you've built isn't reliability—it's ostrich mentality.
Dead Letter Queue (DLQ) comes from the classic messaging pattern: when a message fails consumption up to the maximum retry count, or can't be routed, it isn't discarded directly but moved to a dedicated queue awaiting manual or programmatic handling. The value of DLQ is separating "temporary failures" from "permanent failures"—the former self-heal through retries, the latter are isolated to avoid blocking normal traffic, exhausting retry quotas, or masking real failures. There are several practical points when designing DLQ: dead letter messages should retain complete original context (input, error type, attempt count, timestamp, source queue) for reproduction; DLQ must have monitoring and alerting, otherwise it degenerates into a neglected "graveyard"; reprocessing should prioritize manual triggering, and only consider automation after confirming the root cause is fixed, to avoid pouring the same batch of poison tasks back into the main queue repeatedly.
Heartbeat Monitoring Catches Failures Logs Can't
This is the step teams most often skip. They spend days comparing GPT-5 and Claude, then let unattended tasks run on vibes.
Healthchecks.io is one of the simplest approaches: append curl -fsS -m 10 --retry 5 -o /dev/null https://hc-ping.com/your-uuid-here after the cron command. This catches far more than "did cron start"—it also catches machine downtime, cron daemon issues, non-zero exits, tasks running too long, and missing successful completion.
The minimum monitoring checklist for unattended Agents: one heartbeat per scheduled trigger, queue depth alerts, dead letter queue alerts, worker error rate alerts, and "no successful run in X hours" alerts. That last one is the killer—many Agents don't fail loudly, they just quietly stop doing useful things.
Heartbeat Monitoring (Heartbeat / Dead Man's Switch) works in the opposite direction from conventional metric monitoring: it doesn't detect "is something wrong" but "did something that should have happened not happen." The principle is to have tasks proactively ping a monitoring service after successful execution, with a preset expected period on the monitoring side—once the threshold is exceeded without a ping, an alert fires. This "reverse monitoring" catches silent failures that logs and error rate metrics naturally miss: cron daemon crashes, machine downtime, tasks stuck but not exited, non-zero exit codes being swallowed, abnormally long task run times, etc. For unattended Agents, silent stopping is often more dangerous than explicit errors, because it produces no error logs and the team might only discover it weeks later through business data. In terms of implementation, ping URLs from services like Healthchecks.io or Cronitor meet the minimum requirement; the key is having an independent heartbeat for each scheduled trigger, paired with "no successful run in X hours" alerts.
Rules 7-8: Model Failover Is a Policy, Not Magic
Explicit Policy, Not Prompt Magic
The author doesn't want workers philosophically deciding which model "feels right"—he wants rules. For example: GPT-5 times out twice, route to Claude Opus 4.6; Claude gets rate-limited, route to Grok 4.20 or Qwen; if the fallback model changes the output shape, validate the schema before side effects.
Failover logic goes in the worker's policy layer, where retries, timeouts, and schema validation already live. Write a callModelWithFailover that tries providers in a list, each with a timeout, and after success calls validateResponseSchema before returning. If you use OpenAI-compatible tooling, switching providers doesn't require rewriting the whole application, which makes explicit failover easy to implement.
The key isn't "magic routing," but: turning model selection into an operational policy rather than hidden behavior.
The Stack You Can Ship This Week
If you want to ship a 7×24 unattended Agent by Friday, here's how the author would build it: trigger layer with cron, GitHub Actions, webhook, or n8n timer; queue layer with BullMQ on Redis, or managed SQS/Cloudflare Queues; idempotency with business-derived keys; workers as stateless Node.js workers or n8n queue mode; retries with exponential backoff; dead letter isolation for poison tasks; health checks with Healthchecks.io heartbeats plus queue alerts; model failover with explicit timeouts and fallback rules; compute layer with OpenAI-compatible endpoints that don't penalize retries.
The project structure isn't complicated either: enqueue/ for enqueue scripts, workers/ for workers, lib/ for idempotency, model routing, and schemas, monitoring/ for heartbeat scripts. This stack isn't glamorous—that's exactly why it's trustworthy.
A Final Reminder
Most Agent content talks about memory, planning, autonomy, and reasoning. These are certainly important. But a mediocre Agent with good queues, idempotency, retries, and monitoring will beat a smart Agent that runs twice, dies silently, retries side effects infinitely, and disappears over the weekend.
If you remember only one sentence: First make the Agent boring, then make it smart. Smart is an optional configuration; boring is the survival skill in production.
Whether you're building Agents on n8n, Make, Zapier, OpenClawAd, or a self-built Node.js worker, optimize for reliability first, then for model intelligence. When your "simple cron Agent" first encounters real traffic, this trade-off becomes obvious.
One-line Summary
Treat AI Agents as ordinary background jobs: cron only enqueues, idempotency, layered retries, dead letter and heartbeat both essential.
Paragraph Summary
The article argues for stopping treating AI Agents as magical reasoning machines and engineering them as ordinary background jobs. The core principle is that cron only creates tasks and doesn't execute Agent logic directly, persisting through queues consumed by workers. Duplicate triggers should be handled as an idempotency problem, using business-derived keys and dedicated idempotency tables to ensure side effects happen only once, rather than relying on queue history or AI judgment. Retries must happen inside worker execution steps with exponential backoff, where model calls and external APIs live. The tool selection criterion is whether the team can operate it correctly at 2 AM, not feature strength. Dead letter queues isolate permanent failures, and heartbeat monitoring catches silent failures where Agents quietly stop working. Model failover should be an explicit timeout and fallback policy. The conclusion: first make the Agent boring, then make it smart.
Related articles

Chain of Thought Isn't Just for AI: How Humans Can Use CoT to Improve Thinking Quality
Chain of Thought isn't just a prompt trick for large models. Starting from a Hacker News discussion, this article analyzes why CoT works for human thinking too, breaks down actionable ways to transfer it, and highlights the key differences between human CoT and machine CoT.
Cloudflare Teams Up with OpenAI: Closi…
Cloudflare Teams Up with OpenAI: Closing the Loop from Vulnerability Discovery to Defense with AI
Cloudflare uses OpenAI Daybreak to investigate security vulnerabilities and generate reviewable remediation plans, while developers use Codex to boost coding efficiency and quality.

Orca Multi-Agent Orchestration in Practice: A Guide to Parallel Collaboration with Claude and Codex
Orca is Stable AI's free open-source agent workbench supporting 34 agents like Claude Code and Codex in parallel. Learn its Git worktree isolation, multi-model orchestration, and mobile management.