开发者社区> shy丶gril> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

分享一个异步任务在遇到IO异常时支持递归回调的辅助方法

简介:
+关注继续查看
复制代码
public void TryAsyncActionRecursively<TAsyncResult>(
    string asyncActionName,
    Func<Task<TAsyncResult>> asyncAction,
    Action<int> mainAction,
    Action<TAsyncResult> successAction,
    Func<string> getContextInfoFunc,
    Action<Exception> failedAction,
    int retryTimes) where TAsyncResult : AsyncOperationResult
{
    var retryAction = new Action<int>(currentRetryTimes =>
    {
        if (currentRetryTimes >= _immediatelyRetryTimes)
        {
            Task.Factory.StartDelayedTask(_retryIntervalForIOException, () => mainAction(currentRetryTimes + 1));
        }
        else
        {
            mainAction(currentRetryTimes + 1);
        }
    });
    var executeFailedAction = new Action<Exception>(ex =>
    {
        try
        {
            if (failedAction != null)
            {
                failedAction(ex);
            }
        }
        catch (Exception unknownEx)
        {
            _logger.Error(string.Format("Failed to execute the failedCallbackAction of asyncAction:{0}, contextInfo:{1}",
                asyncActionName, getContextInfoFunc()), unknownEx);
        }
    });
    var processTaskException = new Action<Exception, int>((ex, currentRetryTimes) =>
    {
        if (ex is IOException)
        {
            _logger.Error(string.Format("Async task '{0}' has io exception, contextInfo:{1}, current retryTimes:{2}",
                asyncActionName, getContextInfoFunc(), currentRetryTimes), ex);
            retryAction(retryTimes);
        }
        else
        {
            _logger.Error(string.Format("Async task '{0}' has unknown exception, contextInfo:{1}, current retryTimes:{2}",
                asyncActionName, getContextInfoFunc(), currentRetryTimes), ex);
            executeFailedAction(ex);
        }
    });
    var completeAction = new Action<Task<TAsyncResult>>(t =>
    {
        if (t.Exception != null)
        {
            processTaskException(t.Exception.InnerException, retryTimes);
            return;
        }
        if (t.IsCanceled)
        {
            _logger.ErrorFormat("Async task '{0}' was cancelled, contextInfo:{1}, current retryTimes:{2}",
                asyncActionName, getContextInfoFunc(), retryTimes);
            retryAction(retryTimes);
            return;
        }
        var result = t.Result;
        if (result.Status == AsyncOperationResultStatus.IOException)
        {
            _logger.ErrorFormat("Async task '{0}' has io exception, contextInfo:{1}, current retryTimes:{2}, errorMsg:{3}",
                asyncActionName, getContextInfoFunc(), retryTimes, result.ErrorMessage);
            retryAction(retryTimes);
            return;
        }
        if (successAction != null)
        {
            successAction(result);
        }
    });

    try
    {
        asyncAction().ContinueWith(completeAction);
    }
    catch (IOException ex)
    {
        _logger.Error(string.Format("Execute async action '{0}' failed, contextInfo:{1}, current retryTimes:{2}",
            asyncActionName, getContextInfoFunc(), retryTimes), ex);
        retryAction(retryTimes);
    }
    catch (Exception ex)
    {
        _logger.Error(string.Format("Execute async action '{0}' failed, contextInfo:{1}, current retryTimes:{2}",
            asyncActionName, getContextInfoFunc(), retryTimes), ex);
        executeFailedAction(ex);
    }
}
复制代码

该函数的功能是:执行一个异步任务(返回Task的方法),如果执行出现IO异常,则重试当前主函数(mainAction);用户的mainAction中会再次调用TryAsyncActionRecursively方法。从而实现当遇到IO异常时,能做到不断重试。另外,重试只立即重试指定的次数,超过指定次数,则不立即重试,而是暂停一定间隔后再次执行。该函数还提供当acyncAction执行成功或失败后的回调函数,以及允许传入当前上下文的一些说明信息,以便记录有意义的错误日志信息。

下面是使用示例:

复制代码
private void PublishEventAsync(ProcessingCommand processingCommand, EventStream eventStream, int retryTimes)
{
    TryAsyncActionRecursively<AsyncOperationResult>("PublishEventAsync",
    () => _eventPublisher.PublishAsync(eventStream),
    currentRetryTimes => PublishEventAsync(processingCommand, eventStream, currentRetryTimes),
    result =>
    {
        _logger.DebugFormat("Publish events success, {0}", eventStream);
        processingCommand.Complete(new CommandResult(CommandStatus.Success, processingCommand.Command.Id));
    },
    () => string.Format("[eventStream:{0}]", eventStream),
    ex => processingCommand.Complete(new CommandResult(CommandStatus.Failed, processingCommand.Command.Id)),
    retryTimes);
}
复制代码
PublishEventAsync(processingCommand, eventStream, 0);

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
IO实战篇:投票选举 | 带你学《Java语言高级特性》之七十九
通过前几节的实战,相信读者已经对实现java功能的基本开发过程有了一个十分清晰的理解,最后,让我们“重操旧业”,使用student类实战投票选举的功能。
1024 0
IO实战篇:用户登录 | 带你学《Java语言高级特性》之七十八
本节将带领读者实战用户登录功能,通过输入指定的用户名和密码简单实现用户登录功能来进一步掌握IO相关的知识和其他基本知识。
884 0
IO实战篇:数据排序处理 | 带你学《Java语言高级特性》之七十五
本节将带着读者开发实际案例,以简单基类为单位,结合Comparable接口、工厂设计模式实现对数据的排序功能。
807 0
IO实战篇:数据排序处理深入 | 带你学《Java语言高级特性》之七十六
在上一节中我们实现了简单的输入一些数据并完成数据排序处理的功能,本节将进一步开发,使其实现将数据保存进文件并进行显示的功能。
737 0
IO实战篇:奇偶数统计 | 带你学《Java语言高级特性》之七十七
在前几节中我们实战了很多案例,本节将带着读者开发一个较为简单的实际案例,实现对输入的数字的奇偶数字的出现次数的统计功能。
970 0
IO实战篇:字符串逆序显示 | 带你学《Java语言高级特性》之七十四
本节将带着读者开发实际案例,结合Arrays类和StringBuffer类,实现对字符串的逆序输出操作。
867 0
IO实战篇:数字大小比较 | 带你学《Java语言高级特性》之七十二
本节将带着读者开发实际案例,实现对输入的数字大小的比较功能,并求出所输数字的最大值和最小值。
734 0
IO实战篇:文件保存 | 带你学《Java语言高级特性》之七十三
本节将带着读者开发实际案例,复习File类和文件流的相关基本知识,实现对文件的新建和内容保存等操作。
911 0
Java IO流关闭问题之原理简析
当有嵌套的流时即流被封装,在关闭的时候无论是关闭最外面的还是最里面的都是一样的,因为最外面的包装流的close的方法其实就是调的最里面的流的close方法。所以择其一关闭即可。参考链接:https://blog.
1078 0
+关注
文章
问答
文章排行榜
最热
最新
相关电子书
更多
多IO线程优化版
立即下载
详解ZStack与阿里云的深度融合
立即下载
面向失败设计
立即下载