Gebouw DataBridge: synchronisatie van 20 onafhankelijke 4D systemen met een centrale MySQL backend
Sommige softwareprojecten zijn glamourus. Deze is het niet. Het leeft in de achtergrond, werkt terwijl iedereen slaapt en wordt alleen opgemerkt wanneer het faalt. Dat is precies waarom het belangrijk is.
We zijn momenteel bezig met de ontwikkeling van onze DataBridge-laag: een synchronisatie-motor die ongeveer 20 onafhankelijke 4D-installaties verbindt met een centrale MySQL-backend die de website en aanverwante online diensten bedient. De uitdaging is niet alleen het verplaatsen van gegevens van A naar B. De echte uitdaging is het veilig, herhaaldelijk en voorspelbaar doen in een live productieomgeving waar gebruikers werken, records veranderen, verbindingen kunnen verdwijnen, en geen machine mag de bron van chaos worden.
In het centrum van dit werk is een klasse die DBStructure uitbreidt. Het fungeert als de orkestregisseur voor synchronisatie. Het weet of synchronisatie actief is, waar het externe eindpunt woont, of triggers zijn ingeschakeld, of een synchronisatiecyclus al loopt, wat de laatste HTTP-fout was en welke records zijn veranderd. Het onderhoudt ook een verzameling evenementen luisteraars zodat open Windows binnen de 4D-applicatie kan reageren wanneer afgelegen veranderingen arriveren. Met andere woorden, het is niet alleen een transportlaag. Het is ook de coördinatielaag tussen de database, het netwerk en de gebruikersinterface.
De architectuur volgt een eenvoudig maar gedisciplineerd model. Lokale veranderingen worden eerst door middel van triggers vastgelegd. Wanneer een record wordt gemaakt, gewijzigd of verwijderd, probeert de trigger niet onmiddellijk te synchroniseren met de externe server. In plaats daarvan schrijft het een vermelding in een lokale RecordSync-reeks. Het ontkoppelt databasebewerking van netwerkcommunicatie, wat betekent dat een gebruiker die een record opslaat niet hoeft te wachten op een externe server, een HTTP-oproep of een tijdelijk connectiviteitsprobleem.
Als de achtergrond synchronisatie loop wakker wordt, begint het met het testen of het externe eindpunt bereikbaar is. Als de verbinding gezond is, verricht de brug twee verschillende fasen. Eerst duwt het lokale wachtrijwijzigingen naar buiten. Door deze verantwoordelijkheden onderscheidend te houden, wordt de code gemakkelijker te bedenken en wordt het mislukte gedrag veel gemakkelijker te beheersen.
De local-to-remote fase leest rijlijnen uit RecordSync, op volgorde, bouwt een payload en stuurt het in batches. Elke payload bevat de tabelnaam, de staat van het record, de primaire sleutelinformatie en, indien relevant, de gedetailleerde entiteitsgegevens zelf. Als een partij met succes is geconstateerd, worden de overeenkomstige wachtrij-inslagen verwijderd. Als de verzending faalt, worden ze opzettelijk op hun plaats gelaten zodat de volgende cyclus ze opnieuw kan proberen. Dit is geen flitsende techniek, maar het is het soort dat systemen eerlijk houdt.
De inkomende kant is even voorzichtig. De brug vraagt de server hoeveel wijzigingen wachten na het laatste bekende volgorde nummer, haalt ze in blokken, en vervangt ze één voor één in de lokale 4D datastore. Elke inkomende verandering wordt geclassificeerd als gemaakt, gewijzigd of verwijderd. Nieuwe records worden gecreëerd als ze nog niet bestaan. gewijzigde records worden opnieuw geladen in de overeenkomende entiteit. Na verwerking wordt het lokale opgeslagen volgorde geteld zodat de machine precies weet waar het zich in de stroom bevindt.
Dit klinkt eenvoudig totdat je de oudste vijand van elke synchronisatie-machine ontmoet: recursion. Als een verwijderde wijziging lokaal wordt geschreven en die schrijven een nieuwe uitgaande verandering veroorzaakt, kan het systeem in een eindeloze echokamer draaien. De brug gebruikt daarom een triggerKey om de opnamen te markeren die momenteel van verwijderde synchronisatie worden toegepast. Wanneer de lokale trigger opgaat, herkent hij dat de verandering afkomstig is van de brug zelf en negeert het.
Een andere stille maar essentiële detail is het sluiten. In een echte applicatie kunnen gebruikers al een record open hebben wanneer een afstandsopdatering aankomt. In plaats van een save te dwingen, gegevens te overschrijven of in een slotconflict te storten, probeert de brug eerst de entiteit te sluiten. Als het niet kan, registreert het de situatie en laat het item voor een latere cyclus. Dit is een bewuste ontwerpkeuze: veilig uitstellen in plaats van te doen alsof concurrerende problemen niet bestaan.
De synchronisatielaag schrijft progressupdates naar een paletvenster, volgt de verwerkte rekords, opslaat HTTP-fouten en registreert elke belangrijke gebeurtenis in een synchronisatie logbestand. Ontwikkelaars die werken aan achtergrondinfrastructuur weten deze waarheid goed: als er iets misgaat om 03:12 in de ochtend, is het verschil tussen een vijf minuten durende correctie en een vier uur durende onderzoek meestal de kwaliteit van de logging.
Naast de normale inkrementele synchronisatie bevat de brug ook operationele gereedschappen. Het kan volledige tafels naar de remote backend duwen, afgelegen tafels terugbrengen naar 4D, afgelegen tafels maken en lokale en afgelegen structuren vergelijken. Dat maakt het nuttig niet alleen voor dagelijkse synchronisatie, maar ook voor installatie, migratie, diagnostics en gecontroleerde herstel scenario's. Een synchronisatie-motor wordt veel waardevoller wanneer het het systeem kan verklaren, niet alleen verplaatsen.
Voor ontwikkelaars ligt dit project in een interessante ruimte tussen klassieke zakelijke software en gedistribueerde systeemtechniek. Aan de ene kant is er 4D: volwassen, lokaal, transactioneel, betrouwbaar. Aan de andere kant is er een centraal MySQL ondersteund webplatform dat verwacht consistentie over veel machines en veel gebruikers. DataBridge bestaat in de smalle passage tussen die werelden. Het vertaalt niet alleen gegevens, maar ook timing, staat, mislukking, opnieuw proberen, volgorde en vertrouwen.
Er is nog veel werk te doen. Synchronisatie-motoren worden nooit echt afgerond; ze worden verfijnd, gehardeerd en nieuwe edge cases geleerd in de loop van de tijd. Maar elke verbetering brengt het systeem dichter bij wat de ontwikkelaars daadwerkelijk van de infrastructuur willen: iets betrouwbaar genoeg om te vergeten. Uiteindelijk is dat het hoogste compliment dat een dergelijk onderdeel kan ontvangen. Niet applaus, maar stilte.