我个人会创建自己的方法属性来解决这个问题。
我写了一些
伪
你的密码,基于最初的飞机失火
attribute
在Github上。
实施示例:
[FileNotFoundExceptionNoRetry(Attempts = 10)]
public void ProcessFilesJob()
{
try
{
}
catch (Exception)
{
throw;
}
}
理论上,如果
FileNotFoundException异常
引发异常并继续对任何其他异常重试。
我的改动在
国家选举
方法。
请记住这是未经测试的代码。
public sealed class FileNotFoundExceptionNoRetryAttribute : JobFilterAttribute, IElectStateFilter, IApplyStateFilter
{
private static readonly ILog Logger = LogProvider.GetCurrentClassLogger();
private const int DefaultRetryAttempts = 10;
private int _attempts;
public FileNotFoundExceptionNoRetryAttribute()
{
Attempts = DefaultRetryAttempts;
LogEvents = true;
OnAttemptsExceeded = AttemptsExceededAction.Fail;
}
public int Attempts
{
get { return _attempts; }
set
{
if (value < 0)
{
throw new ArgumentOutOfRangeException("value", "Attempts value must be equal or greater than zero.");
}
_attempts = value;
}
}
public AttemptsExceededAction OnAttemptsExceeded { get; set; }
public bool LogEvents { get; set; }
public void OnStateElection(ElectStateContext context)
{
var failedState = context.CandidateState as FailedState;
if (failedState != null && failedState.Exception != null && failedState.Exception is FileNotFoundException)
{
Attempts = 0;
OnAttemptsExceeded = AttemptsExceededAction.Fail;
}
if (failedState == null)
{
return;
}
var retryAttempt = context.GetJobParameter<int>("RetryCount") + 1;
if (retryAttempt <= Attempts)
{
ScheduleAgainLater(context, retryAttempt, failedState);
}
else if (retryAttempt > Attempts && OnAttemptsExceeded == AttemptsExceededAction.Delete)
{
TransitionToDeleted(context, failedState);
}
else
{
if (LogEvents)
{
Logger.ErrorException(
String.Format(
"Failed to process the job '{0}': an exception occurred.",
context.JobId),
failedState.Exception);
}
}
}
private void ScheduleAgainLater(ElectStateContext context, int retryAttempt, FailedState failedState)
{
context.SetJobParameter("RetryCount", retryAttempt);
var delay = TimeSpan.FromSeconds(SecondsToDelay(retryAttempt));
const int maxMessageLength = 50;
var exceptionMessage = failedState.Exception.Message;
context.CandidateState = new ScheduledState(delay)
{
Reason = String.Format(
"Retry attempt {0} of {1}: {2}",
retryAttempt,
Attempts,
exceptionMessage.Length > maxMessageLength
? exceptionMessage.Substring(0, maxMessageLength - 1) + "â¦"
: exceptionMessage)
};
if (LogEvents)
{
Logger.WarnException(
String.Format(
"Failed to process the job '{0}': an exception occurred. Retry attempt {1} of {2} will be performed in {3}.",
context.JobId,
retryAttempt,
Attempts,
delay),
failedState.Exception);
}
}
private void TransitionToDeleted(ElectStateContext context, FailedState failedState)
{
context.CandidateState = new DeletedState
{
Reason = String.Format("Automatic deletion after retry count exceeded {0}", Attempts)
};
if (LogEvents)
{
Logger.WarnException(
String.Format(
"Failed to process the job '{0}': an exception occured. Job was automatically deleted because the retry attempt count exceeded {1}.",
context.JobId,
Attempts),
failedState.Exception);
}
}
private static int SecondsToDelay(long retryCount)
{
var random = new Random();
return (int)Math.Round(
Math.Pow(retryCount - 1, 4) + 15 + (random.Next(30) * (retryCount)));
}
public void OnStateApplied(ApplyStateContext context, IWriteOnlyTransaction transaction)
{
if (context.NewState is ScheduledState &&
context.NewState.Reason != null &&
context.NewState.Reason.StartsWith("Retry attempt"))
{
transaction.AddToSet("retries", context.JobId);
}
}
public void OnStateUnapplied(ApplyStateContext context, IWriteOnlyTransaction transaction)
{
if (context.OldStateName == ScheduledState.StateName)
{
transaction.RemoveFromSet("retries", context.JobId);
}
}
}