Mi è capitato un problema bizzarro, ultimamente, uno dei tanti in cui mi sto scontrando lavorando con siti con alto traffico di utenti.
Il problema in questione era che il DataReader, improvvisamente, è “impazzito”, restituendo una System.IndexOutOfRangeException nel metodo GetOrdinal. In pratica, mi diceva che nel set di dati restituito mancava la colonna che cercava di leggere. Peccato che, nel metodo in questione, la colonna ci fosse, la stored fosse corretta… insomma, funzionasse tutto “normalmente”. Come nel classico dei bachi, il problema si presentava in maniera assolutamente randomica. Quindi, per esempio, andava perfettamente in 10 casi, l’undicesimo esplodeva.
Il progetto in questione utilizza un mio “storico” data access helper, utilizzato ormai in una marea di progetti anche con più traffico, e più importanti, di questo. Quindi, ho cercato in altri punti il problema, senza arrivare a soluzione alcuna. Mi sono quindi rimesso in discussione, ed ho ricontrollato il data access, trovandolo senza falla (per fortuna!). L’unico dubbio che mi è, per fortuna, venuto, riguarda il fatto che il progetto era gestito da un’altra azienda, cui ho dato alcune dritte, ma che poteva tranquillamente aver male interpretato le mie istruzioni. Quindi, vado a rivedere _come_ è stato utilizzato il mio data access… ed ho trovato la magagna!
In sostanza, il mio data access ha la possibilità di operare in ambiente multi transazionale. Aprendo una transazione, ed una connessione, il data access si predispone a “transazionare” tutti gli oggetti di business in un determinato contesto. Senza questa funzionalità attiva, il data access si predispone per aprire, utilizzare, e richiudere subito la connessione in modo da rimandarla nel pool. L’utilizzo improprio, invece, ha fatto in modo che la connessione venisse aperta _fuori da un contesto transazionale_, e poi di fila venivano chiamati 5 o 6 metodi che riempivano un reader e lo consumavano, chiudendolo ma senza utilizzare CommandBehavior.CloseConnection. Alla fine di tutto, veniva chiusa la connessione.
Senza nessun contesto transazionale attivo, e vista l’intrinseca concorrenzialità di un progetto web, succedeva che i dati del datareader venissero “mischiati” da una chiamata arrivata tra la lettura e l’effettivo consumo del reader. Ho trovato una buona spiegazione di questo problema in questo post sul forum. Per risolvere è bastato rimuovere le connessioni aperte e chiuse in maniera programmatica, e lasciare fare a lui il suo lavoro.
E con questo siamo a due problemi di concorrenza su thread nel corso di una sola settimana… è un segno che, in giro, si fa troppa poca attenzione a questo genere di problematiche? :)