2016-02-25 15 views
9

Chcę napisać kod opakowania do wywołań w bazie danych (przy użyciu języka C# i technologii firmy Microsoft służących do uzyskiwania dostępu do bazy danych), automatycznie ponawiając próby przy wyjątku "przejściowym". Przez przemijające, mam na myśli to, że istnieje duża szansa, że ​​ostatecznie rozwiąże to (wbrew logicznym błędom, które nigdy nie zadziałają). Przykłady, które mogę myśleć to:Numery wyjątków przejściowych serwera SQL

  • Deadlock
  • Connection Timeout
  • Timeout Polecenie

ja zaplanowałem na wykorzystaniu numerów błędów SQLException w celu wykrycia tych. Tak więc na przykład:

List<RunStoredProcedureResultType> resultSet = null; 
int limit = 3; 
for (int i = 0; i < limit; ++i) 
{ 
    bool isLast = i == limit - 1; 
    try 
    { 
     using (var db = /* ... */) 
     { 
      resultSet = db.RunStoredProcedure(param1, param2).ToList(); 
     } 
     //if it gets here it was successful 
     break; 
    } 
    catch (SqlException ex) 
    { 
     if (isLast) 
     { 
      //3 transient errors in a row. So just kill it 
      throw; 
     } 
     switch (ex.Number) 
     { 
      case 1205: //deadlock 
      case -2: //timeout (command timeout?) 
      case 11: //timeout (connection timeout?) 
       // do nothing - continue the loop 
       break; 
      default: 
       //a non-transient error. Just throw the exception on 
       throw; 
     } 
    } 
    Thread.Sleep(TimeSpan.FromSeconds(1)); //some kind of delay - might not use Sleep 
} 
return resultSet; 

(. Przepraszam za ewentualne błędy - Właśnie napisane, że w locie ja też sobie sprawę, mogę owinąć go ładnie ...)

więc kluczową kwestią jest : jakie liczby powinienem uważać za "przejściowy" (zdaję sobie sprawę z tego, co uważam za przejściowe może być inne od tego, co inni uważają za przejściowe). Znalazłem ładną listę tutaj:

https://msdn.microsoft.com/en-us/library/cc645603.aspx

ale jego masywny i pamiętać, bardzo przydatne. Czy ktoś inny zbudował listę, której używają do czegoś podobnego?

UPDATE

W końcu zdecydowaliśmy się na „liście złych” - jeśli błąd jest jednym z listą znanych „non-nieustalonych błędów” - które są zazwyczaj błędy programistyczne. Podaję listę numerów, których używamy jako odpowiedzi.

+1

zrobiliśmy coś podobnego. nazwał to "możliwymi do odzyskania wyjątkami". w tym błędy łączności, limity czasu i zakleszczenia. ale: zakleszczenia najprawdopodobniej wytrwają, gdy trzykrotnie powtórzysz połączenie - rozważ dodanie zmiennego opóźnienia lub innych metod rozwiązywania zakleszczeń. a przekroczenie limitu czasu połączenia z powodu przeciążenia może się jeszcze pogorszyć, gdy natychmiast wykonasz dwie próby. – dlatikay

+0

O tak, zaplanowałem opóźnienie. Dzięki @dlatikay - zaktualizuje powyższe – thab

+0

Witam, prosisz o rekomendację, niestety nie jest to rozwiązanie, ponieważ każdy programista może mieć inne zdanie na temat tego, co byłoby przydatne dla twojego przypadku, więc ze sposobem, w jaki jest obecnie redagowany nie ma tematu; pozdrowienia. – jclozano

Odpowiedz

2

Przepraszamy za własne pytanie, ale jeśli ktoś nadal jest zainteresowany, właśnie zaczęliśmy budować własną listę kodów błędów. Nie idealne, ale doszliśmy do wniosku, że to nie powinno się zdarzać zbyt często.

Zdecydowaliśmy się na podejście "złą listę", zamiast "dobrej listy", jak sugerowano w pytaniu. Identyfikatory mamy do tej pory to:

PARAMETER_NOT_SUPPLIED = 201; 
CANNOT_INSERT_NULL_INTO_NON_NULL = 515; 
FOREGIN_KEY_VIOLATION = 547; 
PRIMARY_KEY_VIOLATION = 2627; 
MEMORY_ALLOCATION_FAILED = 4846; 
ERROR_CONVERTING_NUMERIC_TO_DECIMAL = 8114; 
TOO_MANY_ARGUMENTS = 8144; 
ARGUMENT_IS_NOT_A_PARAMETER = 8145; 
ARGS_SUPPLIED_FOR_PROCEDURE_WITHOUT_PARAMETERS = 8146; 
STRING_OR_BINARY_TRUNCATED = 8152; 
INVALID_POINTER = 10006; 
WRONG_NUMBER_OF_PARAMETERS = 18751; 

Inną rzeczą, jaką zauważyłem jest to, że jeśli czasy Bilard spośród was nie dostać SQLException - zamiast pojawić się komunikat „upłynął limit czasu” InvalidOperationException. Szkoda, że ​​nie jest to wyjątek SqlException, ale warto go złapać.

Postaram się to uaktualnić z dodatkami.

1

Brak kanonicznej listy kodów, które można powtórzyć. Inne zespoły miały już ten problem. Zespół EF opracował strategię ponownej próby. Możesz najechać ich kod. Ale lista nie jest kompletna. Widziałem, jak EF działa na GitHub, gdzie zmienili listę.

Miałem również ten problem. Dodałem kilka oczywistych kodów błędów, które wykopałem z SELECT * FROM sys.messages WHERE language_id = 1033 AND text LIKE '%...%'. Następnie dodałem kody, gdy napotkała je aplikacja.

Należy również ponowić próbę na specjalnym numerze błędu w przypadku przekroczenia limitu czasu i błędu sieci. Serwer nie może wygenerować tego numeru, ponieważ połączenie zostało przerwane. Myślę, że liczba wynosiła -2, ale musisz się upewnić.

Poziomy błędów zdefiniowane przez program SQL Server są bezużyteczne w tym celu (i najczęściej w ogóle).

6

Istnieje klasa [SqlDatabaseTransientErrorDetectionStrategy.cs] w sql Azure dla tymczasowej obsługi błędów. Obejmuje on prawie wszystkie typy kodów wyjątków, które można uznać za przejściowe. Jest to również kompletna implementacja Retry strategy.

Dodawanie fragment tutaj na przyszłość:

/// <summary> 
/// Error codes reported by the DBNETLIB module. 
/// </summary> 
private enum ProcessNetLibErrorCode 
{ 
    ZeroBytes = -3, 

    Timeout = -2, 
    /* Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding. */ 

    Unknown = -1, 

    InsufficientMemory = 1, 

    AccessDenied = 2, 

    ConnectionBusy = 3, 

    ConnectionBroken = 4, 

    ConnectionLimit = 5, 

    ServerNotFound = 6, 

    NetworkNotFound = 7, 

    InsufficientResources = 8, 

    NetworkBusy = 9, 

    NetworkAccessDenied = 10, 

    GeneralError = 11, 

    IncorrectMode = 12, 

    NameNotFound = 13, 

    InvalidConnection = 14, 

    ReadWriteError = 15, 

    TooManyHandles = 16, 

    ServerError = 17, 

    SSLError = 18, 

    EncryptionError = 19, 

    EncryptionNotSupported = 20 
} 

Dalsze przypadek przełącznik aby sprawdzić, czy numer błędu zwrócony w sql wyjątku:

switch (err.Number) 
{ 
    // SQL Error Code: 40501 
    // The service is currently busy. Retry the request after 10 seconds. Code: (reason code to be decoded). 
    case ThrottlingCondition.ThrottlingErrorNumber: 
     // Decode the reason code from the error message to determine the grounds for throttling. 
     var condition = ThrottlingCondition.FromError(err); 

     // Attach the decoded values as additional attributes to the original SQL exception. 
     sqlException.Data[condition.ThrottlingMode.GetType().Name] = 
      condition.ThrottlingMode.ToString(); 
     sqlException.Data[condition.GetType().Name] = condition; 

     return true; 

    // SQL Error Code: 10928 
    // Resource ID: %d. The %s limit for the database is %d and has been reached. 
    case 10928: 
    // SQL Error Code: 10929 
    // Resource ID: %d. The %s minimum guarantee is %d, maximum limit is %d and the current usage for the database is %d. 
    // However, the server is currently too busy to support requests greater than %d for this database. 
    case 10929: 
    // SQL Error Code: 10053 
    // A transport-level error has occurred when receiving results from the server. 
    // An established connection was aborted by the software in your host machine. 
    case 10053: 
    // SQL Error Code: 10054 
    // A transport-level error has occurred when sending the request to the server. 
    // (provider: TCP Provider, error: 0 - An existing connection was forcibly closed by the remote host.) 
    case 10054: 
    // SQL Error Code: 10060 
    // A network-related or instance-specific error occurred while establishing a connection to SQL Server. 
    // The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server 
    // is configured to allow remote connections. (provider: TCP Provider, error: 0 - A connection attempt failed 
    // because the connected party did not properly respond after a period of time, or established connection failed 
    // because connected host has failed to respond.)"} 
    case 10060: 
    // SQL Error Code: 40197 
    // The service has encountered an error processing your request. Please try again. 
    case 40197: 
    // SQL Error Code: 40540 
    // The service has encountered an error processing your request. Please try again. 
    case 40540: 
    // SQL Error Code: 40613 
    // Database XXXX on server YYYY is not currently available. Please retry the connection later. If the problem persists, contact customer 
    // support, and provide them the session tracing ID of ZZZZZ. 
    case 40613: 
    // SQL Error Code: 40143 
    // The service has encountered an error processing your request. Please try again. 
    case 40143: 
    // SQL Error Code: 233 
    // The client was unable to establish a connection because of an error during connection initialization process before login. 
    // Possible causes include the following: the client tried to connect to an unsupported version of SQL Server; the server was too busy 
    // to accept new connections; or there was a resource limitation (insufficient memory or maximum allowed connections) on the server. 
    // (provider: TCP Provider, error: 0 - An existing connection was forcibly closed by the remote host.) 
    case 233: 
    // SQL Error Code: 64 
    // A connection was successfully established with the server, but then an error occurred during the login process. 
    // (provider: TCP Provider, error: 0 - The specified network name is no longer available.) 
    case 64: 
    // DBNETLIB Error Code: 20 
    // The instance of SQL Server you attempted to connect to does not support encryption. 
    case (int)ProcessNetLibErrorCode.EncryptionNotSupported: 
     return true; 
} 

Zobacz pełną source here.

+1

To jest dobre. Wystarczy dodać notatkę, że ta lista wciąż nie jest kompletna. EF jest tak samo nieświadomy tego, jak wszyscy inni. Zapominają przedmiotów. Przykład: konflikty zapisu izolacji w migawce. Również nie widzę zakleszczenia na tej liście, co oznacza listę bardzo wątpliwej wartości. – usr

+0

Tak .. Zgadzam się !!Ale na początek jest to dobra lista. – vendettamit

+0

Dzięki @vendettamit - wygląda dobrze, ale jak wspomina Usr, fakt, że nie trafia w impas, sprawia, że ​​czuję się trochę podejrzanie, ponieważ jest to prawdopodobnie jedna z głównych rzeczy, którymi chciałbym się spierać. Chyba nie jest to coś, na co EF może po prostu zdecydować się na ponowienie automatycznie? – thab

Powiązane problemy