2016-02-25 2 views
9

Я хочу написать некоторый код оболочки для вызовов моей базы данных (используя C# и технологию Microsoft для доступа к базе данных), авто-повтор в случае исключения «переходного». Переходным я имею в виду то, что есть хороший шанс, который в конечном итоге разрешится (в отличие от логических ошибок, которые никогда не будут работать). Примеры, которые я могу думать о том, включают:Sql Server Transition Exception Numbers

  • Тупик
  • Время ожидания соединения
  • Команда таймаут

я планировал использовать номера ошибок SqlException, чтобы обнаружить их. Так, например:

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; 

(. Простите за любые ошибки - я только что написал, что на лету, я также понимаю, что я мог бы обернуть его красиво ...)

Таким образом, ключевым вопросом является : какие числа следует считать «переходными» (я понимаю, что я считаю переходным, может отличаться от того, что другие считают временной). Я нашел хороший список здесь:

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

, но его массивная и отметить очень полезно. Кто-нибудь еще создал список, который они используют для чего-то подобного?

UPDATE

В конце концов, мы остановили свой выбор на «плохой» список - если ошибка является одним из списка известных «без переходных ошибок», - которые, как правило, программист ошибки. Я включил список номеров, которые мы используем в качестве ответа.

+1

мы сделали что-то подобное. назвал его «восстанавливаемыми исключениями». включая ошибки подключения, тайм-ауты и взаимоблокировки. но: взаимоблокировки, вероятно, будут сохраняться, когда вы просто повторите вызов трижды - подумайте о добавлении переменной задержки или других методов разрешения взаимоблокировок. и таймаут соединения из-за перегрузки может также ухудшиться, если вы сразу же запустите два повторных попытки. – dlatikay

+0

О да, я планировал задержку. Спасибо @dlatikay - обновит выше – thab

+0

Привет, вы просите рекомендации, к сожалению, это не разрешимый вопрос, потому что у любого программиста может быть другое мнение о том, что было бы полезно для вашего дела, поэтому так, как оно в настоящее время отредактировано это не в тему; С уважением. – jclozano

ответ

2

Извините, что ответили на мой вопрос, но если кому-то все еще интересно, мы только начали создавать собственный список кодов ошибок. Не идеально, но мы полагали, что это не должно происходить слишком часто.

Мы выбрали подход «плохого списка», а не «хороший список», как подразумевается в вопросе. Идентификаторы мы имеем до сих пор являются:

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; 

Другая вещь, которую мы заметили, что если время пула подключений из вас не получают SqlException - вместо этого вы получите InvalidOperationException отчетов «Время ожидания истекло». Это позор, а не исключение SqlException, но его стоит поймать.

Я постараюсь держать это в курсе любых дополнений.

1

Нет канонического списка повторяющихся кодов. Раньше у других команд была эта проблема. Команда EF разработала стратегию повторных попыток. Возможно, вы захотите совершить набег на их код. Но список не является полным. Я видел, как EF фиксирует GitHub, где они внесли поправки в список.

У меня была эта проблема. Я добавил некоторые очевидные коды ошибок, которые я выкопал из SELECT * FROM sys.messages WHERE language_id = 1033 AND text LIKE '%...%'. Затем я добавил коды, поскольку приложение столкнулось с ними.

Вам также необходимо повторить попытку по специальному номеру ошибки для таймаута и сетевой ошибки. Сервер не может сгенерировать этот номер, потому что соединение отключено. Я думаю, что число было -2, но вам нужно убедиться.

Уровни ошибок, которые SQL Server определяет, бесполезны для этой цели (и в основном в целом).

6

Существует класс [SqlDatabaseTransientErrorDetectionStrategy.cs] в sql Azure для временной обработки ошибок. Он охватывает почти все типы кода исключения, которые можно считать переходными. Также это полная реализация Retry strategy.

Добавление фрагмента кода здесь для дальнейшего использования:

/// <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 
} 

Далее переключатель случай, чтобы проверить, если номер ошибки возвращается в SQL исключения:

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; 
} 

Посмотреть полную source here.

+1

Это хорошо. Просто добавив примечание, что этот список еще не завершен. EF так же не знает об этом, как и все остальные. Они забывают предметы. Пример: изоляция записи моментальных снимков. Также я не вижу тупика в этом списке, что означает список очень сомнительной ценности. – usr

+0

Да .. Я согласен!Но это хороший список для начала. – vendettamit

+0

Спасибо @vendettamit - выглядит хорошо, но, как упоминает usr, тот факт, что он пропустил тупик, заставляет меня чувствовать себя немного подозрительно, потому что это, вероятно, один из главных, на что мне было бы интересно повторить попытку. Наверное, может быть, это не то, что EF может просто решить автоматически повторить попытку? – thab