2012-04-17 7 views
6

Ho un'applicazione web abbastanza grande che utilizza LINQ-TO-SQL in esecuzione in Azure e sto riscontrando errori transitori da SQL-Azure e pertanto è necessario implementare i tentativi. Sono consapevole delle Transient Fault Handling Framework e diversi siti che danno esempi di come usarlo, ma sembra che si deve avvolgere ogni uno dei vostri query LINQ in qualcosa di simile a questo:Retry Logic per LINQ-TO-SQL su SQL Azure: implementazioni efficienti?

RetryPolicy retry = new RetryPolicy<MyRetryStrategy>(5, TimeSpan.FromSeconds(5)); 
Result = retry.ExecuteAction(() => 
{ 
    … LINQ query here... 
}); 

Con centinaia di query LINQ nel mio livello dati, questo sembra davvero disordinato, oltre al fatto che molte volte la query non viene effettivamente eseguita fino a quando i risultati non vengono enumerati. Ad esempio, la maggior parte delle mie funzioni nel mio livello dati restituiscono un IQueryable <> al livello aziendale, (il che le rende più flessibili rispetto alla restituzione di un elenco). Ciò significherebbe che devi abbandonare il tuo livello logico di business con la logica del tentativo di database - brutto.

Quindi immagino che per mantenere la logica dei tentativi nel livello dati, dovrei inserire .ToList() su tutte le mie query in modo che vengano eseguite proprio lì, e non nel livello sopra.

Vorrei davvero che ci fosse un modo per implementare la logica dei tentativi in ​​alcune classi base e non dover cambiare tutte le mie query. Sembra che anche EF avrebbe questo problema.

È la vera risposta per cercare di convincere il team di SQL-Azure a eseguire il tentativo automatico, quindi non dobbiamo preoccuparci di ciò nel nostro codice?

risposta

0

Non sono a conoscenza di una buona soluzione, poiché LINQ to SQL non ci consente di intercettare le query. Ma un piccolo refactor può essere d'aiuto. Qualcosa di simile (pseudo codice):

public Result QueryWithRetry(IQueryable query) 
{ 
     RetryPolicy retry = new RetryPolicy<MyRetryStrategy>(5, TimeSpan.FromSeconds(5)); 
    (() => 
    { 
     return retry.ExecuteAction(query); 
    } 
} 

Ora è un po 'più facile da richiamare questo metodo:

Risultato = QueryWithRetry (... query LINQ qui ...);

Tuttavia, è ancora necessario modificare il codice e modificare ogni query.

migliori saluti,

Ming Xu.

+0

Questo aiuta un po ', ma non dovrei ancora preoccuparmi delle query che non vengono effettivamente eseguite fino a più tardi nel codice in cui sono enumerate? Pertanto dovrei investigare veramente ogni query e capire dove viene effettivamente chiamato il database. – PeteShack

+0

Scusa, non riesco a capirti molto bene. Intendi dire che sei preoccupato se qualcosa va storto, sarà più difficile trovare la fonte del problema perché la query è racchiusa all'interno di un nuovo framework? In questo caso, vorrei suggerire di impostare un punto di interruzione su retry.ExecuteAction e scorrere il codice. –

+0

No, voglio solo dire che aggiungere la logica dei tentativi a un'app esistente con centinaia di query sarà un'operazione difficile, soprattutto perché la chiamata al database non si verifica necessariamente nella query linq-to-sql nel livello dati. L'esecuzione della query può essere ritardata fino a quando l'IQueryable non viene effettivamente elencato, cosa che potrebbe verificarsi nel livello aziendale. Non sembra proprio essere una soluzione pulita a questo problema. – PeteShack

1

Dopo aver implementato qualcosa di simile, sono andato avanti e ho creato una libreria: https://github.com/daveaglick/LinqToSqlRetry (con licenza MIT e disponibile su NuGet).

è possibile riprovare SubmitChanges() chiamate scrivendo SubmitChangesRetry() invece:

using(var context = new MyDbContext()) 
{ 
    context.Items.InsertOnSubmit(new Item { Name = "ABC" }); 
    context.SubmitChangesRetry(); 
} 

Puoi anche riprovare query utilizzando il metodo Retry() estensione:

using(var context = new MyDbContext()) 
{ 
    int count = context.Items.Where(x => x.Name == "ABC").Retry().Count(); 
} 

La logica dei tentativi specifico è controllabile da politiche. Sotto il cofano, il meccanismo di tentativo assomiglia:

int retryCount = 0; 
while (true) 
{ 
    try 
    { 
     return func(); 
    } 
    catch (Exception ex) 
    { 
     TimeSpan? interval = retryPolicy.ShouldRetry(retryCount, ex); 
     if (!interval.HasValue) 
     { 
      throw; 
     } 
     Thread.Sleep(interval.Value); 
    } 
    retryCount++; 
} 

Capire che la funzione nella chiamata a func() e l'oggetto retryPolicy sono fornite in base all'utilizzo. Questo ti dà solo un'idea di cosa sta succedendo durante il ciclo dei tentativi. Basta cercare nel repository per maggiori informazioni.