Communitygithub.com

lguidolin/zero-downtime-migrations

Verwendung bei Datenbankschema-Änderungen, bei denen Daten überleben müssen – Hinzufügen/Entfernen/Umbenennen von Spalten, Constraints, Indizes oder Backfilling. Symptome: eine destruktive Migration, die zusammen mit einem Code-Deploy ausgeliefert wird, eine NOT NULL-Spalte mit Backfill, ein tabellensperrendes UPDATE oder eine Umbenennung.

Was ist zero-downtime-migrations?

Dieses Skill definiert eine disziplinierte Vorgehensweise für Schemaänderungen, die ein laufendes System während eines Rolling-Deploys verfügbar hält. Da während des Rollouts alte und neue Pods auf dieselbe Datenbank zugreifen, muss das Schema gleichzeitig mit beiden App-Versionen kompatibel sein. Der Kern des Skills ist das Expand/Contract-Muster (auch bekannt als Parallel Change), bei dem eine Änderung über drei Releases verteilt wird: Expandieren (neue Struktur additiv hinzufügen), Migrieren (Daten backfillen und auf die neue Struktur umstellen) und Contracting (alte Struktur erst entfernen, wenn die alte App vollständig abgezogen ist). Außerdem werden Postgres-spezifische Fallen und deren sichere Alternativen behandelt, wie z. B. die Verwendung von NOT VALID-Constraints, CREATE INDEX CONCURRENTLY und Timeout-Einstellungen, um Produktionsausfälle zu vermeiden. Der Skill ist primär für Projekte mit persistenten Daten in Postgres-Datenbanken ausgelegt und unterstützt Tools wie graphile-migrate, ist aber allgemein auf jede Deployment-Umgebung übertragbar.

Funktioniert mit~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/lguidolin/agent-skills/tree/main/skills/zero-downtime-migrations

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Zero-Downtime-Migrationen

Übersicht

Schemaänderungsdisziplin, die ein laufendes System während eines Rolling-Deploys aufrechterhält. Während eines Rollouts teilen sich alte und neue Pods eine Datenbank – daher muss das Schema mit beiden App-Versionen gleichzeitig kompatibel sein. Eine destruktive Migration zusammen mit dem Deploy, der sie benötigt, ist der klassische selbstverschuldete Ausfall.

Erstellungsregeln (alle Projekte)

  • Zwei Arten von Migrationen, getrennt gehalten: das idempotente current/-Set (Entwicklungsiteration – wird bei jedem Durchlauf erneut ausgeführt, CREATE OR REPLACE / IF NOT EXISTS, Objekte in endgültiger Form, kein nachträgliches ALTER) und committete Migrationen (unveränderlich, geordnet, was tatsächlich ausgeliefert wird). ALTER DEFAULT PRIVILEGES ist das einzige akzeptierte Inline-ALTER.
  • Die Eigentümerschaft ergibt sich daraus, wie Migrationen ausgeführt werden, nicht aus verstreuten ALTER ... OWNER.
  • Eine Bootstrap-Quelle der Wahrheit, die vom lokalen/Docker-Init-Pfad und der Shadow/Test-DB gemeinsam genutzt wird – jede Umgebung wird identisch aufgebaut.

Expand/Contract (Parallel Change)

Gilt für: wenn die Datenbank Daten enthält, die den Deploy überleben müssen (Staging-mit-Daten, Produktion). Ausgenommen: lokale/Reset-freundliche Projekte – aber schreibe committete Migrationen so, als ob dies gilt, damit eine Promotion nie eine Neuschreibung erfordert.

Eine Schemaänderung wird auf drei Releases aufgeteilt, nie auf einen:

  1. Expandieren – füge die neue Form additiv hinzu, abwärtskompatibel: neue nullable Spalte, neue Tabelle, neue Funktion. App-Version N läuft unverändert weiter.
  2. Migrieren – Backfill in begrenzten Batches (nie ein tabellensperrendes UPDATE); Dual-Write aus App N+1 falls nötig; Lesevorgänge auf die neue Form umstellen. Erst jetzt NOT NULL hinzufügen (Constraint NOT VALID setzen, dann VALIDATE getrennt durchführen).
  3. Contracting – erst nachdem App N vollständig zurückgezogen ist, die alte Spalte/das alte Constraint in einem späteren Release entfernen.

Postgres-Fallen

FalleSicherer Ansatz
NOT NULL-Spalte mit volatilem/großem Backfill-StandardwertNullable hinzufügen → Backfill in Batches → Constraint NOT VALID hinzufügen → VALIDATE
Hinzufügen eines ConstraintsZuerst NOT VALID hinzufügen, dann VALIDATE CONSTRAINT (schwächere Sperre)
Erstellen eines IndexCREATE INDEX CONCURRENTLY – kann nicht in einer Transaktion ausgeführt werden; vom Transaktions-Wrapping des Migrationstools isolieren
Eine blockierte Migration friert die Produktion einlock_timeout / statement_timeout setzen, damit sie schnell fehlschlägt
Umbenennen einer SpalteEs ist Expand/Contract: neue hinzufügen → Backfill → Lesevorgänge umstellen → alte löschen, über mehrere Releases

Warum „CREATE OR REPLACE in Endform“ in der Produktion nicht ausreicht

Diese Regel dient der Entwicklerergonomie und ist in der Entwicklung korrekt. In der Produktion mit echten Nutzern und einem Rolling-Deploy teilen sich beide App-Versionen das Schema für die Dauer des Rollouts – daher sorgt Expand/Contract für die sichere Änderung. Vermische die beiden nicht.

Vollständige Begründung: Artikel XVII der Verfassung, gebündelt unter engineering-constitution/references/engineering-constitution.md. Deploy-Pipeline: cloud-delivery-aks.

Individual skills in this repo

This repo contains 18 individual skills — each has its own dedicated page.

lguidolin/change-hygiene-and-code-craft

Use when writing or refactoring code, structuring a commit or PR, or deciding whether to abstract duplication. Symptoms — mixing reorg with logic changes, a PR doing several things at once, a file growing large, the second copy of similar code, or unsure whether to DRY something up.

lguidolin/cloud-delivery-aks

Use when deploying to Kubernetes or Azure Kubernetes Service (AKS), configuring cloud secrets, setting up progressive rollout/canary, per-PR ephemeral environments, or k8s health probes. Keywords — Kubernetes, AKS, Key Vault, Argo Rollouts, Flagger, canary, blue-green, liveness, readiness, PodDisruptionBudget, HPA, rollback, GHCR.

lguidolin/commit-history-rewrite

Use when an existing repository has messy commit history that needs to conform to conventional commits before adopting release-please, or when intermediate WIP/fixup/merge commits need to be cleaned up.

lguidolin/conventional-commits-and-releases

Use when committing, writing a commit message, opening a PR that will be squash-merged, or configuring automated versioning/changelogs. Keywords — conventional commits, release-please, semver, feat/fix/chore, breaking change, changelog.

lguidolin/defense-in-depth-security

Use when handling untrusted input, secrets, authentication/authorization, or dependencies — or threat-modeling a new surface. Keywords — STRIDE, threat model, least privilege, secrets management, supply chain, dependency scanning, input validation, audit log, defense in depth.

lguidolin/designing-before-building

Use when starting a feature, fixing a non-trivial bug, or about to write implementation code — before any code exists. Symptoms you need this: "this is simple, I'll just code it", reaching for the editor before a design is approved, or an idea that hasn't been turned into a spec and plan.

lguidolin/engineering-constitution

Use when starting work in a project that follows the engineering constitution, orienting to its rules, or deciding which engineering practice applies to a task — spec writing, commits, testing, security, deploys, database, or UI work.

lguidolin/graphql-contract-testing

Use when writing a GraphQL query/mutation that the UI and a test will share, or building route/schema contract or smoke tests. Symptoms — copying a query into a test, a test asserting on query text, schema change that didn't break the UI build, or RLS/permission drift. Keywords — graphql-codegen, typed document, contract test, route smoke test.

lguidolin/init-repo-CI

Use when setting up a new repository with conventional commits, release-please, and CI automation, or when retrofitting an existing repository that lacks automated versioning and PR validation workflows.

lguidolin/interface-craft-and-accessibility

Use when building or styling UI — components, layouts, forms, design tokens — or making accessibility decisions. Keywords — a11y, WCAG, keyboard navigation, focus state, contrast, design system, minimalist UI, component reuse, ARIA, semantic HTML.

lguidolin/merge-gates-and-automation

Use when setting up or changing CI, pre-push hooks, or a task runner, or deciding what must pass before merge. Symptoms — tempted to put authoritative checks only in a local hook, skip CI, bypass with --no-verify, or unsure what gates a merge vs. runs locally.

lguidolin/observability-and-slos

Use when adding logging, metrics, tracing, health checks, SLOs, or alerting — or when building a service surface that needs to be operable and debuggable. Keywords — structured logs, OpenTelemetry, correlation id, RED metrics, liveness, readiness, SLI, SLO, error budget, alerting.

lguidolin/performance-and-scale

Use when working on hot paths, list endpoints, pagination, data-access in loops, or public interfaces/schemas. Symptoms — unbounded queries, N+1 access, no latency budget, optimizing without measuring, or changing an interface many consumers depend on. Keywords — pagination, N+1, Hyrum's Law, performance budget, bundle size.

lguidolin/postgres-postgraphile-rls-and-sql

Use when writing PostgreSQL, PostGraphile config, Row-Level Security policies, SQL schema files, or working on the Browser→App→PostGraphile→Postgres data path. Keywords — RLS, SECURITY DEFINER, search_path, pgSettings, grants, roles, GraphQL depth limit, query cost, statement_timeout, SQL file organization.

lguidolin/recording-decisions

Use when a design or architecture decision has been made and needs to be captured — writing a decision record or ADR, updating a decision index, noting a deferred idea, or superseding a past decision. Keywords — ADR, decision record, rationale, rejected alternatives, dependency index.

lguidolin/resilience-and-deploy-safety

Use when planning a deploy, designing a rollback, or responding to an incident or writing a postmortem. Keywords — deploy safety, rollback, immutable artifact, progressive delivery, canary, blast radius, incident response, blameless postmortem, error budget.

lguidolin/ship-it

Use when the user wants to ship work — push, PR, archive decision records, merge, and clean up. Handles the full lifecycle from committing final changes through post-merge cleanup including converting specs/plans to compact decision records.

lguidolin/tests-as-a-control

Use when writing or modifying tests, when a test breaks during a refactor, or when testing permission/role rules. Symptoms — tempted to edit a test to make it pass, testing only the happy path, a deny-test that started passing, flaky tests, or unsure what to assert.

Verwandte Skills