En overførsel mellem databaser dør, når VPN-forbindelsen falder, og »kør det igen« er ikke en gendannelsesplan. Kildeudtrækket kan være færdigt, målet kan allerede have committet, eller svaret kan simpelthen være gået tabt på vejen tilbage. De tre tilstande kræver forskellige handlinger, og en klient, der kun kender »fejl«, kan ikke skelne dem.

Løsningen er arkitektonisk: giv hver kørsel en varig batch-identitet, og lad databaserne svare på spørgsmål i stedet for at lade klienten gætte.

Hvad databasen faktisk garanterer

SQL Server og Oracle giver begge atomicitet inde i en transaktion. Ingen af dem giver dig atomicitet på tværs af de to. En mistet forbindelse ødelægger ikke databasen og tvinger heller ikke en manuel rollback, fordi serveren afgør sin egen transaktion uden dig. Det, der bryder, er kalderens viden om resultatet.

Committet separat betyder committet separat. Et VPN, der bærer begge forbindelser, smelter ikke to commits sammen til én arbejdsenhed.

Den commit, du aldrig hørte om

Én fejltilstand straffer naiv genopforsøgslogik: serveren committer, og bekræftelsen når aldrig kalderen. Oracle dokumenterer dette som problemet med ukendt resultat og tilbyder Transaction Guard til det i transaktionsdokumentationen. En kommunikationsfejl er ikke bevis for, at en indsendt commit mislykkedes, og at behandle den som bevis er måden, hvorpå en batch bliver sendt to gange. Forskellen er vigtigst på genopforsøgsvejen, hvor operatøren har en fejlmeddelelse og intet andet signal at handle på.

Så gendannelsestrinet skal læse resultatet fra målet i stedet for at udlede det af fejlteksten.

Giv overførslen en batch-identitet

Hver kørsel får et uforanderligt batch-ID, og målet registrerer, hvad det gjorde med det ID. Livscyklussen er fire trin, og den ser ens ud uanset leverandør:

  1. Udtræk en identificeret, uforanderlig kildebatch med et registreret skema og en registreret grænse.
  2. Overfør den til målets stagingområde, og afdæk ufuldstændigt eller modstridende indhold, før den erklæres klar.
  3. Anvend den under målets egne regler for entydighed eller låsning, og registrér færdiggørelsen i den samme lokale transaktion.
  4. Afstem det varige resultat via den understøttede protokol, før der bekræftes eller forsøges igen.

Genopforsøg genbruger ID'et. Et nyt ID for hvert forsøg underminerer den dubletforebyggelse, du netop har bygget, hvilket lyder indlysende, indtil en genopforsøgsindpakning automatisk genererer et.

ID'et giver dig også noget at afstemme imod senere, længe efter at klientprocessen er væk.

Krev batchen, og anvend den derefter

Anvendelsestrinet skal kræve batch-ID'et, foretage forretningsændringerne og registrere færdiggørelsen i én lokal transaktion. Hvis du udfører kontrollen og indsættelsen som separate sætninger, genindfører du det kapløb, du forsøgte at fjerne. Hvis to arbejdere kappes, vinder præcis ét krav, og den anden får besked om det.

En manglende færdiggørelsesregistrering er ikke bevis for, at en igangværende transaktion aldrig committer. Kravet skal serialisere konkurrerende forsøg, eller protokollen skal læse det varige resultat, før der besluttes noget.

Brug databasens understøttede mekanisme til den serialisering i stedet for en tjek-og-gentag-løkke i applikationskoden.

Hvad designet stadig ikke kan love

Staging gør arbejdet genstartbart og reducerer afhængigheden af én langlivet session. Det skaber ikke en enkelt atomisk commit på tværs af SQL Server, Oracle og hvilken som helst ekstern sideeffekt, jobbet udfører. Hvis forretningen virkelig har brug for det, skal du designe og kvalificere en understøttet distribueret transaktion eller en afstemningsproces, herunder hvem der ejer arbejde med usikkert udfald. Alt svagere end det hører i en afstemnings-runbook, ikke i overførselskoden.

Accepter afbrydelse tre steder: under overførsel, under anvendelse og efter commit men før bekræftelse. Kontrollér derefter forretningsresultatet i stedet for klientens meddelelse, og lad batchjournalen sige, om arbejdet er ufuldstændigt, committet eller stadig uafklaret.

Relaterede artikler