Back to all articles
Engineering7 min read

Why We Chose Inngest Over Cron for 24/7 Multi-Tenant Sales Workflows

Jul 18, 2026·By Architecture Team

The Challenge of Multi-Day Sales Workflows

A cold outreach sequence is inherently asynchronous and spans multiple days or weeks: 1. **Step 1**: Send initial personalized email. 2. **Step 2**: Wait 3 business days. If no reply, send Follow-up #1. 3. **Step 3**: Wait 4 business days. If no reply, send Follow-up #2. 4. **Interruption**: At any moment, an inbound reply or out-of-office message must wake up the specific lead workflow and halt further scheduled emails.

---

Why Traditional Cron & Serverless Functions Fail

  • **Serverless Timeouts**: AWS Lambda and Vercel functions timeout after 15–60 seconds; you cannot keep a process alive for 3 days waiting for a delay.
  • **Cron Polling Fragility**: Running a cron job every 5 minutes to poll MongoDB for thousands of pending follow-ups creates race conditions, database lock contention, and missed send windows.
  • **Distributed Concurrency Limits**: Enforcing a strict 30 emails/day cap per mailbox across hundreds of simultaneous campaigns requires complex distributed locking.

---

The Solution: Inngest Durable Execution

17Signal orchestrates campaigns using **Inngest**. This allows us to write straightforward TypeScript workflow functions with built-in durability:

// Send initial touchpoint
await step.run("send-first-email", async () => {
  return await dispatchPersonalizedEmail({ campaign, lead, mailbox });
});

// Sleep for 3 business days without holding any server open await step.sleepUntil("wait-follow-up-delay", nextSendWindowTimestamp);

// Wait for inbound reply or timeout const replyEvent = await step.waitForEvent("inbox/reply.received", { timeout: "3d", match: "data.leadId", });

if (replyEvent) { // Woken by live inbound reply -> Classify & Route await step.run("handle-inbound-reply", async () => { return await handleReplySentiment({ replyEvent }); }); } else { // Timeout reached with no reply -> Send Follow-up await step.run("send-followup-email", async () => { return await dispatchFollowUpEmail({ campaign, lead, mailbox }); }); } ```

Key Advantages - **Zero Server Costs While Sleeping**: When an enrollment sleeps for 3 days, zero compute resources are consumed. - **Instant Event Matching**: When a lead replies via IMAP, Inngest wakes the exact workflow instance in under 200 milliseconds. - **Built-in Rate Limiting**: Per-mailbox concurrency keys guarantee strict adherence to daily send caps and randomized jitter intervals.

Put this into practice

Ready to automate your outbound pipeline?

Experience 60-second domain research and launch your first AI-orchestrated campaign with $50 free credit.

Start free Sign in