A reader pointed out a hole in my last post about idempotency keys, and they were right. This is the follow-up with the fix.
The problem
The simple pattern is: look up the key, run the work, save the response. It breaks in one spot:
def handle ( key , payload ): row = db . get ( key ) if row : return row . response result = do_work ( payload ) # side effect happens here db . insert ( key , result ) # process dies before this line? return result
Enter fullscreen mode
Exit fullscreen mode
If the process dies after do_work() but before insert , the retry sees no row and repeats the side effect. A customer is charged twice.
Fix 1: write a pending row first
import sqlite3 , time , json
db = sqlite3 . connect ( " idem.db " , isolation_level = None ) db . execute ( """ CREATE TABLE IF NOT EXISTS idem ( key TEXT PRIMARY KEY, fingerprint TEXT, status TEXT, response TEXT, created REAL) """ )
def begin ( key , fingerprint ): try : db .…