Ho già parlato nella quinta parte di questa serie della gestione della concorrenza, introducendo la teoria che sottende l'optimistc concorrency così come implementato dall'SDK Azure Mobile, ed esposto aluni codici pratici per gestire la problematica .

In questo momento, però, si sta parlando dell'offline-sync: in tale contesto vedremo che le cose, seppur simili a quanto visto in precedenza, sono giocoforza un pò più complicate.

Inziamo con il dire che per rilevare le modifiche concorrenti la tecnica dall'SDK è sempre la stessa: utilizzo della colonna version (...squadra vincente non si cambia, no ?).

Però nell'online-sync ogni singolo salvataggio viene sottoposto al backend, e quindi l'eventuale gestione della modifica concorrente avviene sul singolo record oggetto del salvataggio.

Nell'offline-sync, invece, a fronte di un singolo push (implicit o meno) si possono sottoporre al backend un numero imprecisato di record modificati, che magari insistono su più tabelle.

Per questo motivo in questo in questo caso potrebbe essere necessario gestire le modifiche concorrenti di più di un record oggetto dell'operazione di push.

Rammento che il push nell'offline-sync sottopone tutte le modifiche avvenute sul database locale SqLite al backend per la loro persistenza sulla base dati remota con lo stesso ordine con cui queste sono avvenute, e richiamando i vari metodi dei controller coinvolti, semplicemente invocando il metodo PushAsync dell'oggetto SyncContext.

Per questo motivo nel caso dell'offline-sync l'SDK Azure Mobile Client mette a disposizione una gestione più articolata della concorrenza, anche se i principi ispiratori sono assolutamente analoghi a quanto già visto.

Aggiungo anche che lavorare con offline-sync sicuramente introduce maggiori probabilità di avere modifiche concorrenti, e un'applicatvo reale dovrebbe poter gestire questa parte in modo preciso e dettagliato sopratutto quando sono coinvolte più tabelle che magari hanno relazioni semantiche tra esse.

Nel seguito un primo esempio di codice utilizzato per gestire i problemi relativi alla concorrenza.

Giunti a questo punto abbiamo la nostra app che serve per condividere i posti dove si mangia la vera focaccia genovese, dotata di gestioe della concorrenza e offline-sync.

Ora però occorre introdurre la possibilità di cancellare in modo corretto un item: più in dettaglio occorre introdurre un meccanismo che permetta a un record, scaricato in modalità offline da più dispositivi e successivamente cancellato da uno di questi che ne ha la facoltà, venga successivamente cancellato anche dal database locale degli altri client mobile coinvolti.

Al momento il meccanismo è questo: un record cancellato da un client viene rimosso al primo push anche sul database Sql Server: sincronizzazioni successive di altri dispositivi non vedranno alcuna traccia di tale record, e quindi lo lasceranno intonso nella propria base dati locale SqLite.

Occorre osservare che questa situazione secondo la logica esposta è assolutamente normale poichè si sta usando la sincronizzazione incrementale, e il record cancellato non viene riproposto in alcun modo nella fase di push incrementale (anzi proprio non esiste più..).

Quindi in una situazione come questa tutti gli altri dispositivi, all'infuori di quello che lo ha realmente cancellato, continueranno ad avere lo stesso record ben presente nella base dati.

Solo una sincronizzazione pull totale e non incremenatel (per esempio reinstallazione totale dell’applicativo, che cancella la base dati locale) non farà più comparire corretamente detto record.

Questa situazione in alcuni casi può essere perfettamente compatibile con le aspettative: in altre assolutamente no.

Gli esempi visti sinora funzionano correttamente: l'unica condizione è che il dispositivo in fase di salvataggio e lettura dei dati abbia a disposizione connettività per potersi connettere al backend.

Inoltre i dati vengono scaricati vengono mantenuti nlla memoria volatile del client: chiudere l'applicativo significa perdere irrimediabilmente le informazioni e la necessità di connettività per riscaricarli.

Inoltre ogni modifica eseguita verrà sottoposta subito al backend per la persistenza su Sql Server.

Detto in altri termini non esiste alcuna persistenza locale, ma solo quella remota su Sql Server, che avviene con l'ausilio del backend ospitato sui servizi Mobile App di Azure.

Per avere la possibilità di salvare il record anche senza connettività, nonchè poter fare delle query sugli stessi dati, occorre introdurre sua maestà l'offline-sync.

Con questo strumento è possibile interagire con un database locale, SqLite, che sarà sincronizzato con il database Sql Server sempre usando i servizi Mobile App Service. Quind tutte le interrogazioni e modifiche avranno come destinatario questo il database locale, e non si avrà necessità di alcuna connessione.

Solo in fase di sincronizzazione del database locale con quello remoto si avrà necessità di connettività per far interagire il client  con i servizi di backend.

Anche per introdurre l'offlie-sync è necessario agire solo sul codice della app (cioè lato client), e la modiifca più notevole è che questa volta si userà l'oggetto che implementa l’interfaccia IMobileServiceSyncTable (prima si usava IMobileServiceTable).

...ovvero la gestione della concorrenza, intesa non come trattare con un'azienda che fa il nostro stesso mestiere ma come "modifiche concorrenti che avvengono sullo stesso dato".

La problematica in analisi nasce dalla seguente situazione. Si immagini il caso in cui in cui la stessa versione di un post all'interno della nostra fantastica app Focac-Book venga modificato da due dispositivi diversi: quale delle due modifiche dovrebbe vincere ??

Per meglio comprendere penso sia utile scendere più nel dettaglio.

Due dispositivi contemporanemente scaricano lo stesso set di dati, che quindi viene mantenuto nella memoria volatile di ciascun dispositivo (la versione della app che stiamo analizzando NON ha ancora l'offline-sync, per cui i dati scaricati rimangono nella memoria volatile di ciscun dispositivo).

In questa condizione guardacaso entrambi i dispositivi modificano lo stesso record, che al salvataggio viene quindi sottoposto al backend.

Questo vuole dire che entrambi gli utilizzatori aprono in modifica lo stesso record, e sui dati presentati (che come detto sono i medesimi) decidono le modifiche da apporvi.

Al salvataggio sul backend quale delle due modiifche dovrebbe vincere ? Il record che è stato oggetto di modifiche è il medesimo ! E un utilizzatore ha fatto delle modifiche basadosi sul valore attuale assunto dal record.

Una prima risposta potrebbe essere che la modifica sottoposta per ultima al backend vince su tutto, e quindi sovrascrive eventuali altre modifiche dall'altro dispositivo.

A pensarci bene, però, questo potrebbe non essere sempre il comportamento desiderato.