在 c# 异常处理中有没有办法检测瞬态错误?
In the c# Exception handling is there a way to detect transient errors?
我正在使用 Azure,我有简单的 try catch 块
我现在正在做的是,当我们遇到任何错误时,我会通过电子邮件发送错误消息,现在我想检测暂时性错误,而忽略为他们发送电子邮件
private void SomeMethod()
{
try
{
// Do stuff
}
catch (Exception ex)
{
HandleError(ex);
return RedirectToAction("Index", "Error");
}
}
protected void HandleError(Exception ex)
{
//and here i want to check if the cause of exception is not a transient error then write a code to email the error details
}
基于您刚刚发布的 link 和提供的代码示例:
// Define your retry strategy: retry 3 times, 1 second apart.
var retryStrategy = new FixedInterval(3, TimeSpan.FromSeconds(1));
// Define your retry policy using the retry strategy and the Azure storage
// transient fault detection strategy.
var retryPolicy =
new RetryPolicy<StorageTransientErrorDetectionStrategy>(retryStrategy);
// Do some work that may result in a transient fault.
try
{
// Call a method that uses Azure storage and which may
// throw a transient exception.
retryPolicy.ExecuteAction(
() =>
{
this.queue.CreateIfNotExist();
});
}
catch (Exception)
{
// All of the retries failed.
}
根据该文档,不会引发异常 直到 它不再是重试策略定义的暂时性错误。实际上 - 利用瞬态故障处理应用程序块已经在做你在问题中所问的事情。重试会静默重试(无一例外),直到出现异常的时间点 - 当重试超出您的重试策略时。
以下不应视为"good code",它只是TFHAB 如何确定一个暂时性错误。
private void DoStuff()
{
try
{
this.DoSomethingThatCouldPotentiallyCauseTransientErrors(5);
}
catch (Exception ex)
{
// This would not be caught until the "retries" have occurred.
this.HandleException(ex);
return RedirectToAction("Index", "Error");
}
}
private void DoSomethingThatCouldPotentiallyCauseTransientErrors(int retryAttemptsBeforeExceptionThrown)
{
// Note that this will *always throw an exception*,
// I'm (attempting to) simply demonstrate my point of how the transient errors could be defined.
for (int i = 0; i < retryAttemptsBeforeExceptionThrown)
{
try
{
int x = 0;
int y = 0;
int result = x / y;
}
catch (Exception)
{
if (i < retryAttemptsBeforeExceptionThrown-1)
{
// Swallow/ignore the exception, and retry
// Note that anything hitting this block would be considered a "transient error",
// as we are not raising an exception
}
else
{
// Too many failed attempts have occurred, ***now*** we raise an exception to the caller
throw;
}
}
}
}
private void HandleException(Exception ex)
{
// Implementation
}
希望这能回答你向 John 提出的有关 "transient error"
的问题
您可以使用来自我的 Apache 许可的信号 Griffin.Framework
public class YourController
{
static Signal _errorsignal = Signal.Create("YourController.Error");
public ActionResult SomeAction()
{
try
{
//some logic
//logic succeeded, reset
_errorSignal.Reset();
}
catch (Exception ex)
{
//Raised for the first time, notify
if (_errorSignal.Raise(ex))
HandleError(ex);
return RedirectToAction("Index", "Error");
}
//[...]
}
它跟踪状态,还可以将状态变化(来自所有信号)上传到 HTTP 服务器。
除了在每个控制器中都出现 HandleError 之外,您还可以将以下内容放入 global.asax:
//put in the Init method
Signal.SignalRaised += OnGlobalHandling;
public void OnGlobalHandling(object sender, SignalRaisedEventArgs e)
{
var signal = (Signal)sender;
//send email
}
如果您使用的是Azure Client SDK(最新版本>= v4.3.0.0),默认重试策略是指数重试。即使您没有专门定义任何重试策略也是如此。客户端 SDK 指数重试策略具有基于几乎从 Azure 存储服务响应返回的 HttpStatusCode 来检测暂时性错误的逻辑。当您向 Azure 存储发出请求并且该请求失败并出现客户端 sdk 认为是暂时的错误(几乎所有 5xx Http 状态代码)时,所有这些重试都将对您的代码透明地完成。
如果你想完全停止客户端 SDK 重试并在你的 catch 块中完全控制它,那么你可以将 NoRetry 策略作为你的 [Table/Blob/Queue]RequestOptions 的一部分来传递由客户端 SDK 完成的后台重试。
然后在你的 catch 块中,你需要捕获客户端 SDK 在你失败的请求时抛出的 StorageException ,解析其中嵌入的 HttpStatusCode ,根据该错误是否为暂时性错误做出决定,并且采取相应的行动。
当然不是所有的异常都是 StorageException ,您也可能会遇到非存储异常,例如 null ref 等。您也可以对这些异常执行相同的处理,它们通常是非瞬态的。
如果你想走那条路,你应该确切地知道你在做什么,实际的客户端 SDK 在它自己的瞬态错误检测和重试机制中做了什么,以及完全关闭它的影响。我见过很多情况,其中 fiddle 使用 Azure 存储 RetryPolicies 的人没有完全理解它的作用,最终导致服务过载,不必要的重试已经由客户端 SDK 重试,或者导致更多的延迟、更低的吞吐量等。
我正在使用 Azure,我有简单的 try catch 块 我现在正在做的是,当我们遇到任何错误时,我会通过电子邮件发送错误消息,现在我想检测暂时性错误,而忽略为他们发送电子邮件
private void SomeMethod()
{
try
{
// Do stuff
}
catch (Exception ex)
{
HandleError(ex);
return RedirectToAction("Index", "Error");
}
}
protected void HandleError(Exception ex)
{
//and here i want to check if the cause of exception is not a transient error then write a code to email the error details
}
基于您刚刚发布的 link 和提供的代码示例:
// Define your retry strategy: retry 3 times, 1 second apart.
var retryStrategy = new FixedInterval(3, TimeSpan.FromSeconds(1));
// Define your retry policy using the retry strategy and the Azure storage
// transient fault detection strategy.
var retryPolicy =
new RetryPolicy<StorageTransientErrorDetectionStrategy>(retryStrategy);
// Do some work that may result in a transient fault.
try
{
// Call a method that uses Azure storage and which may
// throw a transient exception.
retryPolicy.ExecuteAction(
() =>
{
this.queue.CreateIfNotExist();
});
}
catch (Exception)
{
// All of the retries failed.
}
根据该文档,不会引发异常 直到 它不再是重试策略定义的暂时性错误。实际上 - 利用瞬态故障处理应用程序块已经在做你在问题中所问的事情。重试会静默重试(无一例外),直到出现异常的时间点 - 当重试超出您的重试策略时。
以下不应视为"good code",它只是TFHAB 如何确定一个暂时性错误。
private void DoStuff()
{
try
{
this.DoSomethingThatCouldPotentiallyCauseTransientErrors(5);
}
catch (Exception ex)
{
// This would not be caught until the "retries" have occurred.
this.HandleException(ex);
return RedirectToAction("Index", "Error");
}
}
private void DoSomethingThatCouldPotentiallyCauseTransientErrors(int retryAttemptsBeforeExceptionThrown)
{
// Note that this will *always throw an exception*,
// I'm (attempting to) simply demonstrate my point of how the transient errors could be defined.
for (int i = 0; i < retryAttemptsBeforeExceptionThrown)
{
try
{
int x = 0;
int y = 0;
int result = x / y;
}
catch (Exception)
{
if (i < retryAttemptsBeforeExceptionThrown-1)
{
// Swallow/ignore the exception, and retry
// Note that anything hitting this block would be considered a "transient error",
// as we are not raising an exception
}
else
{
// Too many failed attempts have occurred, ***now*** we raise an exception to the caller
throw;
}
}
}
}
private void HandleException(Exception ex)
{
// Implementation
}
希望这能回答你向 John 提出的有关 "transient error"
的问题您可以使用来自我的 Apache 许可的信号 Griffin.Framework
public class YourController
{
static Signal _errorsignal = Signal.Create("YourController.Error");
public ActionResult SomeAction()
{
try
{
//some logic
//logic succeeded, reset
_errorSignal.Reset();
}
catch (Exception ex)
{
//Raised for the first time, notify
if (_errorSignal.Raise(ex))
HandleError(ex);
return RedirectToAction("Index", "Error");
}
//[...]
}
它跟踪状态,还可以将状态变化(来自所有信号)上传到 HTTP 服务器。
除了在每个控制器中都出现 HandleError 之外,您还可以将以下内容放入 global.asax:
//put in the Init method
Signal.SignalRaised += OnGlobalHandling;
public void OnGlobalHandling(object sender, SignalRaisedEventArgs e)
{
var signal = (Signal)sender;
//send email
}
如果您使用的是Azure Client SDK(最新版本>= v4.3.0.0),默认重试策略是指数重试。即使您没有专门定义任何重试策略也是如此。客户端 SDK 指数重试策略具有基于几乎从 Azure 存储服务响应返回的 HttpStatusCode 来检测暂时性错误的逻辑。当您向 Azure 存储发出请求并且该请求失败并出现客户端 sdk 认为是暂时的错误(几乎所有 5xx Http 状态代码)时,所有这些重试都将对您的代码透明地完成。
如果你想完全停止客户端 SDK 重试并在你的 catch 块中完全控制它,那么你可以将 NoRetry 策略作为你的 [Table/Blob/Queue]RequestOptions 的一部分来传递由客户端 SDK 完成的后台重试。
然后在你的 catch 块中,你需要捕获客户端 SDK 在你失败的请求时抛出的 StorageException ,解析其中嵌入的 HttpStatusCode ,根据该错误是否为暂时性错误做出决定,并且采取相应的行动。
当然不是所有的异常都是 StorageException ,您也可能会遇到非存储异常,例如 null ref 等。您也可以对这些异常执行相同的处理,它们通常是非瞬态的。
如果你想走那条路,你应该确切地知道你在做什么,实际的客户端 SDK 在它自己的瞬态错误检测和重试机制中做了什么,以及完全关闭它的影响。我见过很多情况,其中 fiddle 使用 Azure 存储 RetryPolicies 的人没有完全理解它的作用,最终导致服务过载,不必要的重试已经由客户端 SDK 重试,或者导致更多的延迟、更低的吞吐量等。