abbiamo blaterato di servizi WCF e ad un certo punto abbiamo parlato di compensazione, più che parlato abbiamo buttato li la cosa senza approfondire.
Che cavolo stai dicendo Willis?
Un processo compensativo è necessario quando non è possibile, oppure è insensato, pensare ad una transazione (nel senso ACID del termine); una casistica?
Pensiamo ad un long-running-workflow, come ad esempio una commessa per la costruzione di una nave, non è pensabile avviare una transazione al momento T0 e farne il commit 2 anni dopo, ma è comunque necessario trovare un sistema per fare una sorta di rollback delle operazioni anche a distanza di tempo.
è quindi necessario compensare gli effetti di qualcosa che è già avvenuto che è ben diverso dal fare il rollback di una transazione che rappresenta un qualcosa che ancora non è avvenuto.
Avete generalmente due scenari:
  • dovete introdurre un processo compensativo a posteriori (tipicamente perché avete progettato male);
  • dovete pensare un processo compensativo up-front tipicamente perché i dati che manipolate sono distribuiti su basi dati eterogenee su cui non è possibile avere una transazione distribuita (o come abbiamo già avuto modo di dire su cui non ha nessun senso avere una transazione distribuita);
l’altra volta abbiamo detto:
…Sta di fatto che l’atomicità (o presunta tale) dell’operazione la dobbiamo garantire, se non altro perché l’utente si aspetta che se ha uno screen in cui può creare un Employee, assegnarvi un Address e un Department e sullo screen c’è un singolo pulsante salva, il nostro simpatico utente si aspetta che quell’operazione sia atomica, quindi se l’assegnazione dell’Address fallisce non è concepibile che l’Employee esista (punto-fine-della-discussione)…
Supponiamo che abbiate un servizio che gestisce questa logica, ed esponga le 3 operazioni descritte, le tre operazioni ovviamente non sono atomiche, o meglio prese singolarmente si, ma nel loro insieme no; il sistema è in produzione ed è decisamente ostico cambiare radicalmente l’API pubblica per adeguarla in base alle esigente. Questo è un tipico scenario in cui potrebbe aver senso introdurre un processo compensativo basato sulla pubblicazione.
Andiamo un più nel dettaglio del sistema: dietro il servizio WCF c’è un Object Model mappato su un database relazionale con tutti i suoi, sacrosanti, criteri di integrità referenziale.
Potete quindi procedere ad esempio così:
  • introdurre sul modello (e quindi nel database) il concetto di IsPublished, che di default è false;
  • adattare tutti i processi di lettura per estrarre solo i dati che hanno IsPublished impostato a true;
Fino a questo punto i sistemi esterni non si sono accorti di nulla e continuano a funzionare, in lettura, esattamente come prima;
  • aggiungere un’operazione Publish che dato un set di identificatori sia in grado, in maniera transazionale, di cambiare lo stato IsPublished di tutte le entità identificate dal set in un colpo solo;
in scrittura invece succede che apparentemente non scriviamo più nulla, chiamiamo le operazioni sul servizio ma questa sembrano non sortire effetti, ma se al termine di ogni set di operazioni aggiungiamo una chiamata a Publish tutto torna a funzionare come prima.
Quale è il vantaggio?
Molto semplicemente siamo in grado di compensare una failure in un processo che dovrebbe essere atomico ma che purtroppo non lo è. Nella peggiore delle ipotesi se durante il processo di creazione del grafo qualcosa va storto abbiamo degli elementi esistenti ma non pubblicati che quindi è come se non esistessero.
.m