У меня есть метод веб-сервиса, который я называю, который является третьей стороной и за пределами моего домена. По некоторым причинам время от времени веб-сервис перестал работать с тайм-аутом шлюза. Ее неустойчивое и вызов к нему непосредственно после неудачной попытки могут успешно выполниться.
Теперь меня оставляют с дилеммой кодирования, у меня есть код, который должен добиться цели, но код похож на любительский час, как Вы будете видеть ниже.
Этот действительно плохой код, или приемлем, учитывая использование? Если не приемлемый, как я могу улучшить его?
Очень старайтесь сохранить серьезный вид при рассмотрении его.
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.
}
}
}
}
}
Вы можете делать это в цикле.
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);
}
Попробуйте цикл, с каким-то ограничением:
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)
. Поймать более специфическое исключение - то, от которого вы знаете, вы можете безопасно восстановиться.
Как уже указали все, правильный подход - заключить ваш try / catch внутри некоторого цикла с каким-то MAX_RETRY.
Вы также можете рассмотреть возможность добавления тайм-аута между каждой итерацией цикла. В противном случае вы, скорее всего, сожжете счетчик повторов до того, как временная проблема разрешится сама собой.
Вот еще один способ, который вы можете попробовать:
// 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.
}
}
Я думаю, он лучше документирует намерение. Кроме того, это меньше кода; его легче поддерживать.
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 : Исправлен код на основе комментариев.
Вы должны использовать рекурсию (или цикл), и должны повторять попытку только если вы получили ожидаемую ошибку.
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
.
Если последняя повторная попытка не удалась, то будет выброшено последнее исключение.
Попробуйте цикл с некоторым ограничением:
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--;
}
Кажется, у вас есть ответы, которые вам нужны, но я решил разместить эту ссылку, Что такое Action Policy?, которая, как я обнаружил, дает гораздо более элегантное решение. В Lokad есть несколько довольно лабиринтных реализаций, но логика этого парня довольно прочная, и конечный код, который вы в итоге напишете, довольно прост.