Flyway problemenen oplossingen
Onderwerp voor innovatiedag
Maandelijks hebben we bij Eleven een innovatie dag waar iedereen met iets nieuws aan de slag gaat. Dit kan een nieuw framework of nieuwe techniek zijn. Maar het kan ook iets zijn wat irriteert en waarvan je vind dat het beter, sneller of slimmer kan. Zo heb ik mij deze maand geƫrgerd aan problemen met Flyway.
Bij het schrijven van code is versie controle een feature waar we niet meer zonder kunnen. Ondanks dat het oplossen van een merge conflict niet altijd leuk is voorkomt het fouten en forceert het je direct het probleem op te lossen. Bij database migraties werkt dit maar gedeeltelijk.
Versiecontrole voor databases
Binnen het Spring Boot project waar ik aan werk gebruiken we Flyway, een methode om versie controle toe te passen op wijzigingen in je database. Die versie controle werkt door in de database een aparte tabel bij te houden waarin flyway bijhoudt welke migratie scripts er al uitgevoerd zijn. Migratie scripts met een hoger nummer worden daarna uitgevoerd en indien je een script hebt met hetzelfde, of lager, versienummer krijgt je een error. Dit is een mooi begin, maar het betekend dat je build kan slagen terwijl bij het deployen van je code een error voorkomt.
Gedeeltelijk kun je dit met een unit test oplossen, maar zeker wanneer je met verschillende developers op verschillende branches bezig bent geeft dit problemen.
Neem als voorbeeld dit standaard gitflow branch model. Feature-branch (lokaal), sprint-development, hotfixes en Master.
Aan elke branch zit een omgeving gekoppeld en daar draait een aparte instantie van de database.
Wanneer we op hotfixes een db migratie doen, laten we dit V2_fix
noemen, dan is de volgende stap deze code te mergen naar zowel master als naar sprint-development.
Maar sprint-development heeft ook niet stil gestaan en daar staat al een V2_sprint migratie script.
Flyway kijkt vervolgens enkel naar het versienummer en ziet twee scripts met versie 2.
Op dit moment geeft Flyway een error en moet je dit handmatig fixen.
Omdat dingen op de juiste volgorde moeten gebeuren, en master/productie uiteraard leidend is zul je de V2_sprint
migratie moeten terug draaien in de sprint db, het script moeten hernoemen en dan alles opnieuw bouwen.
Hoe anders?
Hoe meer verschillende branches, hoe meer db wijzigingen en hoe meer developers er werken aan een project hoe vaker dit voorkomt. En hoe meer handmatige wijzigingen je doet hoe groter de kans op fouten. Dus ik heb gezocht naar een alternatieve manier. De simpelste manier is om volgorde helemaal uit te zetten binnen flyway, gebruik dan timestamps als versie nummer en flyway voert de migratie uit zodra hij deze ziet.
Het kan voorkomen dat twee scripts dezelfde kolom aanpassen. De ene zet een kolom op NULL
terwijl de andere er NOT NULL
van maakt.
Welke wordt hiervan de eindsituatie? Dat kan per omgeving verschillen.
Het gevaar hiervan is dat je niet een exact te voorspellen en te reproduceren database krijgt op productie. Maar het scheelt ook wel een hoop problemen.
Is daar niet een tussen oplossing voor te bedenken?
Het alternatief
Wat mij betreft wel. Voor nu is het idee om op hotfixes en master de oude situatie te gebruiken, oftewel, op versienummer en volledig reproduceerbaar.
Voor develop en feature branches gaan we wel de spring.flyway.outOfOrder=true
zetten.
Dit combineren we door slim om te gaan met versie nummers.
DB migraties voor hotfixes krijgen een versie nummer als volgt: major.minor.1
en dit loopt sequentieel op.
Voor sprints gebruiken we de volgende versienummers: major.minor.0.timestamp
. Wanneer je iets naar development merged wordt elke migratie (die niet eerder is gedaan) uitgevoerd, ongeacht of dit een hoger of lager versie nummer heeft.
Op het moment dat de sprint naar hotfixes gaat (die bij ons dienst doet als acceptatie) zijn alle eerder migraties al gedaan, worden de sprint db migraties uitgevoerd op volgorde van timestamp en heb je een te reproduceren situatie.
Of dat ook werkt gaan we de komende weken/maanden zien, maar ik verwacht minder flyway migratie en nog steeds een stabiele en reproduceerbare acceptatie/productie database.