Vi har udgivet ddl-mt, en forkortelse for damn delightful migrations, under MIT-licensen. Det er et selvstændigt kommandolinjeværktøj, der anvender SQL-migreringer på PostgreSQL. Denne artikel forklarer, hvilket problem det løser for os, hvilke valg vi har truffet, og hvorfor det er offentligt.
Problemet
Som konsulenter arbejder vi i mange repositories på samme tid. De fleste har en PostgreSQL-database, og de fleste af dem findes i mere end ét miljø. Skemaændringer er en lille del af hvert projekt, og det er samtidig den del, hvor en fejl er sværest at rette op på.
Migreringsværktøjer følger som regel med et applikationsframework eller en ORM. Det fungerer godt inden for ét projekt. På tværs af mange projekter betyder det et nyt værktøj, en ny historiktabel og nye vaner i hvert repository. Vi ville det modsatte: ét værktøj, der opfører sig ens overalt, mens hvert repository stadig ejer sin egen SQL.
Hvad ddl-mt gør
Hvert repository har sine migreringer som nummererede SQL-filer sammen med en lille projektfil, ddl-mt.json. Én installeret binær fil håndterer dem alle.
Projektfilen definerer navngivne targets. Et target forbinder en mappe med migreringer med den database, det forventer, en kilde til adgangsoplysninger og en historiktabel:
{
"project": "shop",
"targets": {
"development": {
"database": "shop_dev",
"migrations_dir": "migrations/main",
"dsn_env": "SHOP_DEV_DSN"
},
"production": {
"database": "shop",
"migrations_dir": "migrations/main",
"dsn_env": "SHOP_PROD_DSN"
}
}
} Udvikling og produktion deler den samme SQL, selvom databaserne hedder noget forskelligt. Det daglige arbejde består af en håndfuld kommandoer:
ddl-mt --target development new create_widgets
ddl-mt --target development validate
ddl-mt --target development status
ddl-mt --target development apply check afslutter med en fejl, når en database har ventende, fejlede eller ændrede migreringer, så den egner sig som et trin i CI. baseline registrerer migreringer, som en eksisterende database allerede indeholder, så en database med historik kan tages i brug uden at køre dens SQL igen.
De valg, vi har truffet
Du angiver altid et target. Der er ingen underforstået standard. Når forbindelsen er oprettet, sammenligner ddl-mt databasens faktiske navn med det, som targetet forventer, og stopper, hvis de er forskellige. En produktionskommando mod den forkerte database skal fejle, før der kører nogen SQL.
Almindelig SQL, kun fremad. Migreringer er SQL-filer, som man kan læse og gennemgå. Hver fil får en kontrolsum, så det bliver opdaget, hvis en anvendt migrering senere bliver redigeret eller omdøbt. Der er ingen ned-migreringer og ingen sammenligning af skemaer. En ændring, der er sat i drift, rettes med en ny migrering.
Hver migrering er atomar. En migrering og dens post i historikken bliver committet i samme transaktion. Hvis migreringen fejler, rulles den tilbage, og intet bliver registreret.
Connection pooling er tænkt ind fra starten. Som standard tager ddl-mt en advisory lock på transaktionsniveau for hver migrering og læser historikken igen, mens låsen holdes. Det virker på en direkte PostgreSQL-forbindelse og bag PgBouncer med transaction pooling eller session pooling, og to kørsler, der starter samtidig, kan ikke anvende den samme fil to gange.
Undtagelserne er eksplicitte. Sætninger som CREATE INDEX CONCURRENTLY kan ikke køre i en transaktion. ddl-mt kører dem kun, når targetet har tilvalgt det og bruger en sessionsforbindelse. Værktøjet skriver en varig markering, før SQL’en starter, og efter en fejl skal en operatør beslutte, om ændringen skal prøves igen eller markeres som anvendt. Værktøjet gætter ikke.
Adgangsoplysninger holdes ude af kommandolinjen. Forbindelsesstrenge kommer fra en miljøvariabel eller en fil med adgangsoplysninger, aldrig fra et argument. Forbindelsesfejl rapporteres som kategorier, for eksempel fejl i godkendelse, DNS eller TLS, uden at forbindelsesstrengen eller serverens rå besked bliver skrevet ud.
Hvad det ikke er
ddl-mt understøtter kun PostgreSQL. Det genererer ikke migreringer, sammenligner ikke skemaer og ruller ikke ændringer tilbage, og det anvender ikke migreringer på alle targets i én kommando. Det er et lille værktøj, og det vil vi gerne holde fast i. Det er også ungt: den første offentlige version er 0.2.0, og der kan stadig komme ændringer i 0.x-serien, som ikke er bagudkompatible.
Hvorfor open source
Vores daglige arbejde hviler på open source: PostgreSQL selv, Go og driveren pgx, som ddl-mt bruger. At udgive et værktøj, som andre kan bruge, er en måde at give noget tilbage på.
Der er også en praktisk grund. Et værktøj, der ændrer produktionsdatabaser, skal være let at efterse. Når kildekoden, testene og ændringsloggen ligger offentligt, kan vores kunder og alle andre brugere læse præcis, hvad det gør, før de stoler på det.
Prøv det
Med Go 1.26 eller nyere:
go install github.com/qbite-tech/ddl-mt@latest
ddl-mt create-config README-filen gennemgår konfiguration, PgBouncer og genopretning i detaljer. Fejlrapporter og bidrag er velkomne i repositoriet, og du kan skrive til os på opensource@qbite.tech.