Повторные попытки в блоке Catch? - PullRequest
7 голосов
/ 09 ноября 2011

Как реализовать код в блоке catch?

  try
    {
       // Call a MS SQL stored procedure (MS SQL 2000)
       // Stored Procedure may deadlock 
    }
    catch
    {
       // if deadlocked Call a MS SQL stored procedure (may deadlock again)
       // If deadlocked, keep trying until stored procedure executes
    }
    finally
    {

    }

Ответы [ 7 ]

24 голосов
/ 09 ноября 2011

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

Но вот как это сделать в цикле:

for(int attempts = 0; attempts < 5; attempts++)
// if you really want to keep going until it works, use   for(;;)
{
    try
    {
        DoWork();
        break;
    }
    catch { }
    Thread.Sleep(50); // Possibly a good idea to pause here, explanation below
}

Обновление: Как упомянул г-н Разочарование вкомментарий ниже: Метод Thread.Sleep приостанавливает выполнение на указанное количество миллисекунд.Ни одна ошибка не является абсолютно случайной, большинство из которых будут работать просто путем повторных попыток , только потому, что что-то изменилось за время, которое потребовалось между попытками.Приостановка выполнения потока даст гораздо больше возможностей для этого (например, больше времени для запуска механизма базы данных).

3 голосов
/ 09 ноября 2011

Как насчет этого

bool retry = true;
while( retry ){
  try{
    ...
    retry = false;
  }
  catch
  {
    ...
  }
  finally
  {
    ...
  }
}

До тех пор, пока запускается последняя строка блока try (retry = false), он будет продолжаться. Если возникает какое-то исключение, он запускает блоки catch и finally, а затем возвращается к началу цикла и снова запускает блок try.

Если вы хотите попробовать только x раз, вы можете заменить повтор на int с начальным значением количества попыток в первую очередь. Затем проверьте, равно ли оно 0 в цикле while, уменьшите его в начале цикла и установите в 0 в качестве последней строки блока try.

И вы, конечно, должны что-то сделать с этим пустым блоком перехвата, чтобы он ловил ожидаемые вами исключения, а не тот, который перехватывает все.

2 голосов
/ 09 ноября 2011

Вы действительно не должны просто забивать базу данных, пока она не выполнит ваш SP, но это уже другая история.

Вы можете сделать это так:

Boolean succeeded = false;

while (!succeeded)
{

    try
    {
        // Call a MS SQL stored procedure (MS SQL 2000)
        // Stored Procedure may deadlock 
        succeeded = true;
    }
    catch (Exception ex)
    {
        // Log
    }
}
2 голосов
/ 09 ноября 2011

Не используйте его в блоке catch. Вместо этого напишите цикл вокруг него, который повторяется до тех пор, пока он не будет успешным или не будет достигнут некоторый предел.

Что-то вроде:

bool quit = false;
int loopcount = 0;
while(!quit )
{
   try
   {
       // execute the command, might throw an exception)
       quit = true; // no exception if you got here
   }
   catch(Exception ex)
   {
      if (ex != deadlock) // doesn't work like this :-(
        quit = true;
   }
   finally
   {
      // etc.
   }
   loopcount++;
   if (loopcount > 3)
      quit = true;
}
1 голос
/ 07 октября 2016

Скопировано дословно со страницы сети разработчиков Microsoft на то, что они называют Шаблон повторов :

private int retryCount = 3;
...

public async Task OperationWithBasicRetryAsync()
{
  int currentRetry = 0;

  for (; ;)
  {
    try
    {
      // Calling external service.
      await TransientOperationAsync();

      // Return or break.
      break;
    }
    catch (Exception ex)
    {
      Trace.TraceError("Operation Exception");

      currentRetry++;

      // Check if the exception thrown was a transient exception
      // based on the logic in the error detection strategy.
      // Determine whether to retry the operation, as well as how 
      // long to wait, based on the retry strategy.
      if (currentRetry > this.retryCount || !IsTransient(ex))
      {
        // If this is not a transient error 
        // or we should not retry re-throw the exception. 
        throw;
      }
    }

    // Wait to retry the operation.
    // Consider calculating an exponential delay here and 
    // using a strategy best suited for the operation and fault.
    Await.Task.Delay();
  }
}

// Async method that wraps a call to a remote service (details not shown).
private async Task TransientOperationAsync()
{
  ...
}

Они более подробно объясняют, как правильно использовать, а как неправильно.этот шаблон.Например, если вы ожидаете, что ошибки, с которыми вы сталкиваетесь, являются временными, и повторная попытка через мгновение, скорее всего, будет успешной, это может быть для вас.Если это поможет вам справиться с некоторыми проблемами масштабирования, это не для вас.

Возможно, вас также заинтересует их Схема автоматического выключателя , которую они описывают как способную "Обрабатыватьошибки, которые могут занимать различное время для устранения при подключении к удаленному сервису или ресурсу. "

1 голос
/ 09 ноября 2011

Это может быть так же просто, как завершение всего цикла try / catch в цикле while:

while (!success) {

    try
    {
       // Call a MS SQL stored procedure (MS SQL 2000)
       // Stored Procedure may deadlock 
       success = true;
    }
    catch
    {
       // if deadlocked Call a MS SQL stored procedure (may deadlock again)
       // If deadlocked, keep trying until stored procedure executes
       success = false;
    }

}
0 голосов
/ 09 ноября 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...