Varför kör en egenhostad app samma databasmigrering två gånger efter en omdistribution?

Eva Wong är Teknisk skribent och den boende fixaren på ZimaSpace. En livslång nörd med en passion för hemma-labb och öppen källkod, hon specialiserar sig på att översätta komplexa tekniska koncept till tillgängliga, praktiska guider. Eva tror att självhosting ska vara roligt, inte skrämmande. Genom sina handledningar ger hon gemenskapen verktyg att avmystifiera hårdvaruinstallationer, från att bygga sin första NAS till att bemästra Docker-containrar.

En databasmigrering kan köras två gånger när fler än en startväg, container eller schemaläggare tror att den ansvarar för samma uppgraderingssteg.

Självhostade applikationer startar ofta migreringar från en entrypoint, webbprocess, worker, sidecar, systemd-enhet eller distributionshook. Efter en omdistribution kan en gammal container överlappa med en ny, en omstartspolicy kan starta om en misslyckad migrering eller två repliker kan nå databasen innan någon av dem registrerar att migreringen är klar. Diagnosen bör identifiera alla potentiella körande processer och fastställa om migreringsramverket använder ett beständigt lås eller en historikpost för schemat innan någon datareparation påbörjas.

Identifiera varje process som kan starta migreringen

Sök i avbildningens entrypoint, Compose-kommandot, worker-kommandot, systemd-enheten, cron-jobbet, distributionsskriptet och applikationens startlogg efter migreringskommandot. Notera process-ID:n och containernamn vid de två körningstillfällena.

Docker Compose kan starta tjänster enligt deklarerade beroenden, men startordningen gör inte i sig en migrering till en applikationsnivå med en enda ägare. Den officiella vägledningen om startordning visar varför en tillgänglig databas och en migrering med en unik ägare är separata villkor.

Om samma kommando finns både i webbprocessens entrypoint och i en dedikerad migreringstjänst ska du ta bort den ena ägaren. Om bara ett kommando finns fortsätter du med att kontrollera repliker, omstartsloopar och poster för migreringstillstånd.

Kontrollera om gamla och nya containrar överlappar

Lista körande, omstartande, avslutade och övergivna containrar under distributionen. Jämför projektnamn, tjänstenamn, container-ID:n och skapandetider.

Systemd dokumenterar att en tjänsts omstartspolicy kan starta om ett misslyckat kommando enligt enhetens inställningar. Dess omstartsmodell för tjänster hjälper till att förklara varför en värdstartare kan köra migreringen igen efter att det containeriserade försöket avslutas med en status som inte är noll.

Ta bort bekräftat övergivna körande processer först efter att du har sparat deras loggar. En andra migreringstidsstämpel strax efter den första avspeglar ofta ett nytt försök snarare än ett separat schemalagt jobb.

Använd ett databasslås innan schemaändringar tillämpas

Ta reda på om applikationen hämtar ett lås på databasnivå innan den läser migreringstillståndet och tillämpar ändringar. Testa två samtidiga uppstartsförsök i en miljö som kan kastas bort.

PostgreSQL tillhandahåller rådgivande lås för applikationsdefinerad samordning, vilket gör att en migreringskörning kan utesluta en annan även när båda startar nästan samtidigt.

Ett lås måste täcka hela besluts- och körningsfönstret. Om den aktuella schemaversionen kontrolleras innan låset hämtas kan två körningar fortfarande välja samma väntande migrering.

Verifiera låssemantiken i MySQL eller MariaDB

För MySQL-kompatibla applikationer ska du kontrollera om migreringsverktyget använder ett namngivet lås, en transaktion eller en låstabell och om anslutningen förblir aktiv under hela migreringen.

MySQL dokumenterar anslutningsbundna namngivna lås, som frigörs när den ägande sessionen avslutas och därför måste hämtas på nytt på ett säkert sätt efter en krasch eller omstart.

En misslyckad anslutning kan frigöra låset innan migreringsramverket registrerar att migreringen är klar. Jämför databasloggar med tidsstämplar för omstarter av containrar för att identifiera detta förlopp.

Granska migreringsramverkets historiktabell

Lista migreringsidentifierare, körordning, lyckad-status, kontrollsummor och tidsstämplar. Jämför de två loggade körningarna med de poster som faktiskt har sparats i databasen.

Flyway använder en schemahistoriktabell för att spåra tillämpade migreringar och deras tillstånd.

Om den första körningen ändrade schemat men misslyckades innan den registrerade att körningen lyckats kan den andra körningen försöka tillämpa en migrering igen trots att den inte skrevs för att vara idempotent. Reparera historiken först efter att du har jämfört det faktiska schemat med migreringens förväntade resultat.

Kontrollera ändringsloggens identitet och förändringar i kontrollsumman

Jämför migreringsfilnamn, ID:n, författare, sökvägar och kontrollsummor före och efter uppdateringen av avbildningen. Ta reda på om avbildningen innehåller duplicerade eller omnamnade poster i ändringsloggen.

Liquibase registrerar körda ändringar i tabellen DATABASECHANGELOG, där ändringens identitet beror på dess ID, författare och filsökväg.

Om en ändringsloggsfil flyttas eller identifierare genereras på nytt kan gammalt arbete verka vara nytt även när SQL-koden liknar den tidigare. Återställ en stabil migreringsidentitet i stället för att manuellt radera stora historikintervall.

Distribuera på nytt med en migreringsägare och verifiera idempotens

Välj en migreringsägare, lägg till ett beständigt lås, låt webb- och worker-tjänsterna vänta tills migreringen har slutförts och distribuera på nytt i en testkopia av databasen.

ZimaSpace-artikeln om schemaläggningsgränser för containrar ger en närliggande regel: en underhållsuppgift bör ha en bevisad körningsägare.

Problemet är löst när samtidiga eller upprepade starter resulterar i en tillämpad migrering, en beständig historikpost och ingen andra schemaändring efter omstart.

Vanliga frågor

Skadar databasen alltid om en migrering körs två gånger?

Nej. Idempotenta migreringar kan på ett säkert sätt upptäcka befintliga objekt, men icke-idempotenta datatransformeringar, skapande av index eller kolumnändringar kan misslyckas eller duplicera data.

Bör varje webb-replik få köra migreringar?

Endast när ramverket tillhandahåller tillförlitlig samordning på databasnivå. En dedikerad migreringsägare som körs en gång är enklare att granska i en hemserverdistribution.

Kan jag markera migreringen som slutförd manuellt?

Endast efter att du har bevisat att det aktiva schemat och datan överensstämmer med migreringens förväntade resultat. Om du redigerar historiken först kan en delvis tillämpad ändring döljas.

Support och tips

Mer att läsa

Get More Builds Like This

Stay in the Loop

Get updates from Zima - new products, exclusive deals, and real builds from the community.

Stay in the Loop preferences

We respect your inbox. Unsubscribe anytime.