Как я могу улучшить этот сценарий повторной попытки исключения?

У меня есть метод веб-сервиса, который я называю, который является третьей стороной и за пределами моего домена. По некоторым причинам время от времени веб-сервис перестал работать с тайм-аутом шлюза. Ее неустойчивое и вызов к нему непосредственно после неудачной попытки могут успешно выполниться.

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

Этот действительно плохой код, или приемлем, учитывая использование? Если не приемлемый, как я могу улучшить его?

Очень старайтесь сохранить серьезный вид при рассмотрении его.

try
{
    MDO = OperationsWebService.MessageDownload(MI);
}
catch
{
    try
    {
        MDO = OperationsWebService.MessageDownload(MI);
    }
    catch
    {
        try
        {
            MDO = OperationsWebService.MessageDownload(MI);
        }
        catch
        {
            try
            {
                MDO = OperationsWebService.MessageDownload(MI);
            }
            catch 
            {
                try
                {
                    MDO = OperationsWebService.MessageDownload(MI);
                }
                catch (Exception ex)
                {
                    // 5 retries, ok now log and deal with the error.
                }
            }
        }
    }
}
22
задан John Saunders 16 February 2010 в 02:30
поделиться

8 ответов

Вы можете делать это в цикле.

Exception firstEx = null;
for(int i=0; i<5; i++) 
{
    try
    {
        MDO = OperationsWebService.MessageDownload(MI);
        firstEx = null;
        break; 
    }
    catch(Exception ex)
    {
        if (firstEx == null) 
        {
            firstEx = ex;
        }
        Thread.Sleep(100 * (i + 1));
    }
}
if (firstEx != null) 
{
    throw new Exception("WebService call failed after 5 retries.", firstEx);
}
21
ответ дан 29 November 2019 в 04:17
поделиться

Попробуйте цикл, с каким-то ограничением:

int retryCount = 5;
var done = false;
Exception error = null;
while (!done && retryCount > 0)
{
    try
    {
        MDO = OperationsWebService.MessageDownload(MI);
        done = true;
    }
    catch (Exception ex)
    {
        error = ex;
    }
    if (done)
        break;

    retryCount--;
}
-121--1605544-
int cnt=0;
bool cont = true;
while (cont)
{
     try
     {
         MDO = OperationsWebService.MessageDownload(MI);
         cont = false; 
     }
     catch (Exception ex) 
     { 
         ++cnt;
         if (cnt == 5)
         {
             // 5 retries, ok now log and deal with the error. 
            cont = false;
         }
     } 
}

ОБНОВЛЕНО: Фиксированный код на основе комментариев.

-121--1605550-

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

Почти никогда не следует использовать голые " catch " или " catch (исключение ex) . Поймать более специфическое исключение - то, от которого вы знаете, вы можете безопасно восстановиться.

11
ответ дан 29 November 2019 в 04:17
поделиться

Как уже указали все, правильный подход - заключить ваш try / catch внутри некоторого цикла с каким-то MAX_RETRY.

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

0
ответ дан 29 November 2019 в 04:17
поделиться

Вот еще один способ, который вы можете попробовать:

// Easier to change if you decide that 5 retries isn't right for you
Exception exceptionKeeper = null;
for (int i = 0; i < MAX_RETRIES; ++i)
{
    try
    {
       MDO = OperationsWebService.MessageDownload(MI);
       break;  // correct point from Joe - thanks.
    }
    catch (Exception ex)
    {
        exceptionKeeper = ex;
        // 5 retries, ok now log and deal with the error.
    }  
}

Я думаю, он лучше документирует намерение. Кроме того, это меньше кода; его легче поддерживать.

12
ответ дан 29 November 2019 в 04:17
поделиться
int cnt=0;
bool cont = true;
while (cont)
{
     try
     {
         MDO = OperationsWebService.MessageDownload(MI);
         cont = false; 
     }
     catch (Exception ex) 
     { 
         ++cnt;
         if (cnt == 5)
         {
             // 5 retries, ok now log and deal with the error. 
            cont = false;
         }
     } 
}

UPDATED : Исправлен код на основе комментариев.

0
ответ дан 29 November 2019 в 04:17
поделиться

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

For example:

static void TryExecute<TException>(Action method, Func<TException, bool> retryFilter, int maxRetries) where TException : Exception {
    try {
        method();
    } catch(TException ex) {
        if (maxRetries > 0 && retryFilter(ex))
            TryExecute(method, retryFilter, maxRetries - 1);
        else
            throw;
    }
}

EDIT:

static void TryExecute<TException>(Action method, Func<TException, bool> retryFilter, int maxRetries) where TException : Exception {
    while (true) {
        try {
            method();
            return;
        } catch(TException ex) {
            if (maxRetries > 0 && retryFilter(ex))
                maxRetries--;
            else
                throw;
        }
    }
}

Вы можете попытаться предотвратить будущие ошибки в retryFilter, возможно, с помощью Thread.Sleep.

Если последняя повторная попытка не удалась, то будет выброшено последнее исключение.

1
ответ дан 29 November 2019 в 04:17
поделиться

Попробуйте цикл с некоторым ограничением:

int retryCount = 5;
var done = false;
Exception error = null;
while (!done && retryCount > 0)
{
    try
    {
        MDO = OperationsWebService.MessageDownload(MI);
        done = true;
    }
    catch (Exception ex)
    {
        error = ex;
    }
    if (done)
        break;

    retryCount--;
}
2
ответ дан 29 November 2019 в 04:17
поделиться

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

0
ответ дан 29 November 2019 в 04:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: