Un trasferimento tra database muore quando la VPN cade, e «eseguilo di nuovo» non è un piano di ripristino. L’estrazione dall’origine può essere completa, la destinazione può aver già eseguito il commit, oppure la risposta può semplicemente essersi persa sulla via del ritorno. Questi tre stati richiedono azioni diverse, e un client che conosce solo «errore» non può distinguerli.

La correzione è architetturale: assegna a ogni esecuzione un’identità di batch durevole, e lascia che siano i database a rispondere alle domande invece di far indovinare il client.

Che cosa garantisce davvero il database

SQL Server e Oracle offrono entrambi atomicità all’interno di una transazione. Nessuno dei due ti offre atomicità tra i due. Una connessione persa non corrompe il database e non impone nemmeno un rollback manuale, perché il server risolve la propria transazione senza di te. Ciò che si rompe è la conoscenza dell’esito da parte del chiamante.

Commit separato significa commit separato. Una VPN che trasporta entrambe le connessioni non fonde due commit in un’unica unità di lavoro.

Il commit di cui non hai mai sentito parlare

Una modalità di errore punisce la logica di retry ingenua: il server esegue il commit, e l’acknowledgment non raggiunge mai il chiamante. Oracle lo documenta come il problema dell’esito sconosciuto e fornisce Transaction Guard per questo nella documentazione sulle transazioni. Un errore di comunicazione non è la prova che un commit inviato sia fallito, e trattarlo come prova è il modo in cui un batch viene pubblicato due volte. La distinzione conta soprattutto sul percorso di retry, dove l’operatore ha un messaggio di errore e nessun altro segnale su cui agire.

Quindi il passo di ripristino deve leggere l’esito dalla destinazione invece di dedurlo dal testo dell’errore.

Dai un’identità di batch al trasferimento

Ogni esecuzione riceve un identificatore di batch immutabile, e la destinazione registra cosa ha fatto con quell’identificatore. Il ciclo di vita ha quattro passi, e appare identico qualunque sia il fornitore:

  1. Estrai un batch di origine identificato e immutabile con schema e confine registrati.
  2. Trasferiscilo nell’area di preparazione della destinazione e rileva contenuti incompleti o in conflitto prima di dichiararlo pronto.
  3. Applicalo secondo le regole di unicità o di blocco della destinazione stessa e registra il completamento nella stessa transazione locale.
  4. Riconcilia l’esito durevole tramite il protocollo supportato prima di confermare o riprovare.

I retry riutilizzano l’identificatore. Un nuovo identificatore per ogni tentativo vanifica la prevenzione dei duplicati appena costruita, il che sembra ovvio finché un wrapper di retry non ne genera uno automaticamente.

L’identificatore ti dà anche qualcosa su cui riconciliare più tardi, molto dopo che il processo client è sparito.

Rivendica il batch, poi applicalo

Il passo di applicazione deve rivendicare l’identificatore di batch, eseguire le modifiche di business e registrare il completamento in un’unica transazione locale. Eseguire il controllo e l’inserimento come istruzioni separate reintroduce la corsa che stavi cercando di rimuovere. Se due worker competono, esattamente una rivendicazione vince e all’altro viene detto.

Un record di completamento assente non è prova che una transazione in corso non eseguirà mai il commit. La rivendicazione deve serializzare i tentativi concorrenti, oppure il protocollo deve leggere l’esito durevole prima di decidere qualsiasi cosa.

Usa il meccanismo supportato dal database per quella serializzazione invece di un ciclo controlla-e-ripeti nel codice dell’applicazione.

Cosa il progetto non può ancora promettere

La preparazione rende il lavoro riavviabile e riduce la dipendenza da un’unica sessione di lunga durata. Non crea un unico commit atomico attraverso SQL Server, Oracle e qualunque effetto collaterale esterno il lavoro produca. Se il business ne ha davvero bisogno, progetta e qualifica una transazione distribuita supportata o un processo di riconciliazione, incluso chi possiede il lavoro dall’esito incerto. Qualunque cosa più debole appartiene a un runbook di riconciliazione, non al codice di trasferimento.

Accetta l’interruzione in tre punti: durante il trasferimento, durante l’applicazione e dopo il commit ma prima dell’acknowledgment. Poi controlla il risultato di business invece del messaggio del client, e lascia che il registro dei batch dica se il lavoro è incompleto, committato o ancora irrisolto.

Articoli correlati