OB_access: The Email Queue That Refuses to Forget

A self-hosted campaign engine that precomputes every send, guards every claim, and rebuilds its own queue when the system drifts.

8 to 10 min read • View on GitHub • More from manishpravesh

A wide editorial scene shows a conveyor of stamped envelopes moving through a machine governed by a central ledger. A clerk in the foreground writes future send times into the ledger, while a broken section of conveyor is bypassed by a repair bridge that reroutes envelopes without stopping the flow. The image explains that the system treats delivery as a durable timeline, not a disposable queue.
OB_access turns a campaign into a visible future, then keeps that future recoverable when the queue breaks.
Key Takeaways

Most mailers optimize for throughput. OB_access optimizes for truth. It turns a campaign into a schedule that can be inspected, retried, and rebuilt, which is a very different promise from “send jobs into a queue and hope.”

The queue that rebuilds itself

The core idea is simple: the database owns the campaign state, not Redis. That means a Redis reset is annoying, but not fatal. If the queue drifts, the system can reconstruct it from Postgres and continue from the last known truth.

That design changes the emotional contract of the app. Instead of hiding delivery behind workers, it exposes the future as rows, timestamps, and states. The result feels less like a mailer and more like a delivery ledger with a repair loop.

Every email gets a time before it gets a job

The standout scheduling move lives in packSchedule. Rather than letting workers decide timing on the fly, the scheduler fans a campaign out into individual Email rows, assigns each one a scheduledAt, and writes them in a transaction.

One campaign moves through scheduling, queueing, claiming, rate limiting, sending, and reconciliation. Postgres stays underneath as the source of truth.

That is a deliberate tradeoff. Precomputing the schedule gives users a clear campaign timeline, but it also means runtime checks still matter. The system chooses visibility first, then protects that visibility with recovery logic when conditions change.

// Conceptual shape of the scheduler
for (const recipient of recipients) {
  const scheduledAt = new Date(startAt.getTime() + offsetMs);
  await prisma.email.create({
    data: {
      campaignId,
      recipient,
      scheduledAt,
      status: 'SCHEDULED'
    }
  });
}

The claim-check-send pattern

The worker is disciplined about state transitions. A job is only claimed if the row is still SCHEDULED, which means competing workers can race but only one can win. That keeps duplicates from turning into chaos.

If a worker stalls or crashes, the system does not leave the row stranded forever. Stalled handling and recovery logic release the claim and let the campaign move forward again, which is exactly what you want from a delivery engine that expects failure.

A close-up scene shows a single sealed envelope with a deterministic ID moving through three narrow gates labeled by their function: scheduled, processing, and sent. A side rail labeled stalled recovery pulls a dropped envelope back into line. The image explains how the worker uses explicit state transitions and recovery to avoid duplicate delivery and stranded jobs.
The worker does not trust optimism. It claims, checks, sends, and recovers by state.

Redis as an atomic gatekeeper

The rate limiter matters because it is atomic. The Redis Lua script checks and increments both global and per-sender counters in one operation, so workers cannot race each other into breaking the hourly ceiling.

When the limit is hit, the job does not fail. It slides into the next hour window. That is a practical compromise, and it fits the whole design philosophy of the project: preserve the campaign, preserve the order, preserve the intent.

ConcernConventional queue mailerOB_access
Scheduling modelComputed at runtime by workersPrecomputed per recipient in the database
Source of truthQueue statePostgres rows and states
Duplicate preventionBest effort dedupeDeterministic job IDs plus claim checks
Rate limitingOften split across worker logicSingle atomic Redis Lua gate
Crash recoveryRequeue and hopeReconcile Redis from Postgres
User visibilityHidden behind jobsVisible campaign timeline

Here the architecture makes its bet obvious. It prefers explicit state over hidden worker behavior, and it prefers a slightly delayed send over a broken one.

Reconciliation is the real superpower

The reconciler is what turns the system from robust into self-healing. On boot, it compares the database against Redis, finds scheduled emails that are missing jobs, and restores the queue from first principles.

That is the project’s real reliability trick. Redis is treated as an execution cache, not as the memory of the system. If Redis disappears, the campaign does not forget itself.

Why this feels different from a normal mailer

Most email tools sell templates, analytics, and delivery volume. OB_access is more interested in temporal determinism, self-repair, and queue truth. That makes it feel closer to a durable task system than a marketing app.

QuestionNormal mailerOB_access
What is the future of the campaign?Implicit inside jobsExplicit in scheduled rows
What happens on failure?Retries and operational cleanupReconciliation reconstructs missing work
What does the user see?A black box until send timeA visible campaign timeline
What does the system trust?The queue and worker lifecycleThe database first, queue second

That is why the project stands out. It does not merely send email. It makes delivery legible, then makes legibility durable.