DEV Community

Niteflex
Niteflex

Posted on

Why we gave our Telegram content bot a "nothing twice" rule

We build Mira (useMira), a Telegram bot with a Mini App that finds and drafts channel posts from sources you add. Early on we kept hitting the same failure mode: a source hiccups, the worker retries, and the same item gets scored and drafted twice. Nothing broke loudly, it just quietly doubled work and occasionally doubled a post in someone's Plan screen.

The rule

We made it a hard rule in the worker: better to skip an item than to process it twice. If a job's outcome is unknown after a crash or a timeout, we don't retry it blindly. It goes to an archive table with a flag, and nothing downstream touches it again automatically.

Why not just retry harder

Retrying harder is the obvious fix, and it's wrong for a content pipeline specifically. A duplicated API call is usually invisible. A duplicated Telegram post is not — it shows up in someone's channel, or as two near-identical drafts competing for the same slot in their Plan. The cost of under-processing (one source gets checked a minute later) is low. The cost of over-processing (two posts, or a scoring pass that double-counts) is a trust problem with a real person's channel.

Where this shows up in practice

  • The queue is Postgres, not a broker. Workers claim jobs with FOR UPDATE SKIP LOCKED, so two workers never pick up the same job and don't block each other waiting.
  • A dead worker means an expired lease, not a stuck job — the job goes back to the queue, but only once, not in a loop.
  • Payment webhooks are idempotent by a unique constraint, not by a "does this exist" check beforehand, because the check-then-act gap is exactly where duplicates sneak in.

None of this is novel — idempotency and SKIP LOCKED are old ideas. What surprised me is how much a "nothing twice" default changes the shape of the whole system once you take it seriously at the content layer, not just the payments layer where everyone already expects it.

If you've solved this differently in your own pipeline — different trade-off, different failure mode — I'd like to hear it in the comments.

More on Mira: https://usemira.pro Bot: https://t.me/usemirabot

Top comments (0)