this post was submitted on 03 Aug 2026
11 points (73.9% liked)

Programming

28091 readers
758 users here now

Welcome to the main community in programming.dev! Feel free to post anything relating to programming here!

Cross posting is strongly encouraged in the instance. If you feel your post or another person's post makes sense in another community cross post into it.

Hope you enjoy the instance!

Rules

Rules

  • Follow the programming.dev instance rules
  • Keep content related to programming in some way
  • If you're posting long videos try to add in some form of tldr for those who don't want to watch videos

Wormhole

Follow the wormhole through a path of communities !webdev@programming.dev



founded 3 years ago
MODERATORS
 

I idemkit after cleaning up duplicate charges one too many times.

The version everyone writes checks whether a key has been seen and replays the stored response. Two requests a millisecond apart both find nothing and both charge the card. And if the worker dies between charging and recording it, the retry charges again. Neither reproduces locally.

idemkit does it properly: an atomic claim instead of check-then-act, a lease that expires on the storage server’s clock, and a fencing token so a stalled worker can’t overwrite a good result.

from idemkit import idempotent, RedisBackend, MethodConfig 

@idempotent(
    backend=RedisBackend.from_url("redis://localhost:6379"), 
    config=MethodConfig(key_fields=["order_id"]), 
) 
async def charge(*, order_id, amount): 
    return await payments.charge(order_id, amount)

One core, three ways to use it: middleware for FastAPI/Flask/Django, a queue consumer wrapper or @idempotent on any function. Backends are Redis, Postgres, Mongo, DynamoDB, or in-memory for tests.

pip install idemkit, Apache-2.0: https://github.com/idemkit/idemkit

If you find it useful, I'd appreciate a star. It's new, so visibility helps a lot right now.

you are viewing a single comment's thread
view the rest of the comments
[–] TehPers@beehaw.org 10 points 1 week ago* (last edited 1 week ago) (1 children)

Code shows signs of LLM use, in case anyone's curious. Unless, of course, you normally type em dashes in your documentation I suppose.

Anyway, this feels to me like a small part of what is essentially a durable task framework. If you need atomicity and durability, consider one of those. If all you need is atomicity, a database guarantees it through so many methods, from inserts to locks*.

*Edit: and transactions, of course, but long running transactions aren't usually a good idea.