首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Hangfire自动重试特定异常

Hangfire自动重试特定异常
EN

Stack Overflow用户
提问于 2018-06-26 16:38:26
回答 1查看 2.4K关注 0票数 1

我使用的作业调度和自动重试作业,我启用了10次。此工作在特定文件夹位置执行文件处理,.In某些场景文件将不在共享位置。我想要的是,如果文件是假的。我不想在绞刑中重试这份工作,而这份工作应该会失败。但其他异常工作应该重试10次。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-08-10 12:08:36

就我个人而言,我会创建自己的方法属性来解决这个问题。

我已经为您编写了一些代码,它是基于github上最初的hangfire 属性编写的。

实施实例:

代码语言:javascript
运行
复制
[FileNotFoundExceptionNoRetry(Attempts = 10)]//Retry 10 times
    public void ProcessFilesJob()
    {
        try
        {
            //Process files in shared location... 
        }
        catch (Exception)
        {
            throw;
        }
    }

理论上,如果引发FileNotFoundException异常并继续对任何其他异常进行重试,下面的属性代码将使作业处于“失败”状态。

我的修改是在OnStateElection方法下进行的。请记住这是未经测试的代码。

代码语言:javascript
运行
复制
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)
        {//FileNotFoundException was thrown dont retry.

            Attempts = 0;
            OnAttemptsExceeded = AttemptsExceededAction.Fail;
        }

        if (failedState == null)
        {
            // This filter accepts only failed job state.
            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);
            }
        }
    }

    /// <summary>
    /// Schedules the job to run again later. See <see cref="SecondsToDelay"/>.
    /// </summary>
    /// <param name="context">The state context.</param>
    /// <param name="retryAttempt">The count of retry attempts made so far.</param>
    /// <param name="failedState">Object which contains details about the current failed state.</param>
    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;

        // If attempt number is less than max attempts, we should
        // schedule the job to run again later.
        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);
        }
    }

    /// <summary>
    /// Transition the candidate state to the deleted state.
    /// </summary>
    /// <param name="context">The state context.</param>
    /// <param name="failedState">Object which contains details about the current failed state.</param>
    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);
        }
    }

    // delayed_job uses the same basic formula
    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);
        }
    }
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51047728

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档