databases
Relational, time-series and the schema decisions that outlive the code.
-
The Transactional Outbox: Never Losing a Job You Already Committed
Committing a database change and then enqueueing a job as two separate steps leaves a gap in which the change is permanent but nothing ever runs the job and nothing notices. This works through the transactional outbox pattern and gives a complete, runnable Postgres, Redis Streams and Python implementation that survives a crash at any point in that gap.
-
Running Alembic Migrations Once, Before the Workers Fork
Calling alembic upgrade head from inside application code means every gunicorn worker, and every replica of the container, races to run the same migration concurrently. This shows why that races, and an entrypoint that migrates exactly once, guarded by a Postgres advisory lock, before the server process ever starts.
-
Preventing Overselling with a Database CHECK Constraint
Code that reads the remaining stock, decides there is enough, and then writes the new total is a race that two concurrent customers can both win, each believing they got the last unit. This article works through why check-then-decrement logic fails under a database's default isolation level, and builds a schema where a single atomic UPDATE together with a CHECK constraint makes overselling structurally impossible rather than merely unlikely, with a concurrency test to prove it.
-
Sizing Redis maxmemory Against a Stream Trim Threshold
Redis Streams trim themselves as a side effect of XADD, and XADD is refused once maxmemory is reached under the default eviction policy. That leaves a gap where a stream can hit the memory ceiling before it ever gets trimmed down, and stay stuck there. Here is how to reproduce that state, why maxmemory-policy will not save you, and how to size and sequence trimming so it cannot happen.