Zero-Downtime Database Migrations with Alembic
How to apply schema migrations in PostgreSQL without table locks or downtime: the expand-and-contract pattern, safe default column additions, and building indexes with CONCURRENTLY in Alembic.
Welcome,
Python & systems developer — writing and building open-source tools
I am Ahmed. I have worked with Python for years, mostly on the backend: FastAPI services, Telegram bots, and small Redis-backed tools.
I write about things I have actually applied in real projects: unifying code, explicit errors, concurrency, Debian deployment, and the tools I built and open-sourced. What you read here comes from experience, with the trade-offs stated honestly.
How to apply schema migrations in PostgreSQL without table locks or downtime: the expand-and-contract pattern, safe default column additions, and building indexes with CONCURRENTLY in Alembic.
Protecting modern FastAPI endpoints against real-world exploits: applying defense-in-depth, tiered rate limiting, eliminating data exposure through strict Pydantic models, and locking down CORS and HTTP headers.
Architecting background worker systems that never lose a job: at-least-once delivery, mastering idempotency against duplicated executions, and dead-letter queue strategies with exponential backoff.
A production-ready async FastAPI template with clean layers (api/core/services/repos), typed config, and Redis used for three distinct concerns: caching, a Lua sliding-window rate limiter, and a distributed lock. Includes JSON logs with request-id, multi-stage Dockerfile and a CI pipeline enforcing quality gates.
An async, Redis-backed job queue for Python. Delivery uses atomic LMOVE/BLMOVE leasing plus a reaper that re-schedules jobs from crashed workers (at-least-once). Includes retries with exponential backoff and jitter, a dead-letter queue, delayed/scheduled jobs, priorities, cooperative cancellation and structured logging.
An idempotent Debian 12 bootstrap: sudo user, hardened SSH, UFW, fail2ban, unattended security upgrades, Docker from the official repo, swap, NTP and systemd templates. Each stage checks state before applying and only changes what needs changing, with a full --dry-run and per-run logs.