c# - 在 C# 中为同步/异步任务添加重试/回滚机制的最佳方法是什么?

标签 c# asp.net .net design-patterns

想象一个 WebForms 应用程序,其中有一个名为 CreateAll() 的主要方法。我可以逐步描述方法任务的过程如下:

1) 存储到数据库(更新/创建 Db 项目 3-4 次)

2) 开始一个新线程

3) Result1 = 调用 soap 服务,并通过使用超时阈值检查状态并在 x 分钟后继续。它继续(现在状态正常,并不意味着失败)

4) 存储到数据库(更新/创建 Db 项目 3-4 次)

5) result2 = 调用 soap 服务(以即刻即弃的方式)

6) 更新配置文件(实际取自 result1)

7) 通过使用回调请求,它会在前面每隔 x 秒检查一次结果 2 的状态,并且 UI 会显示一个进度条。如果过程完成 (100%),则表示成功

我正在考虑所有这些都是可以按类型分组的任务。基本上,几种类型的操作是:

  • 类型 1:数据库事务
  • Type2:服务沟通/交易
  • 类型 3:配置文件 I/O 事务

我想为现有的实现添加回滚/重试机制,并使用面向任务的架构并重构现有的遗留代码。

我发现 C# 中的 Memento Design PatternCommand Pattern 之类的东西可以帮助实现这一目的。我还发现了 msdn Retry Pattern描述很有趣。我真的不知道,我希望有人能引导我做出最安全和最好的决定...

对于这种情况,您能否建议我保留现有实现和流程但将其包装在通用和抽象的重试/回滚/任务列表实现中的最佳方法?

最终实现必须能够在每种情况下重试(无论是什么任务或一般故障,例如整个 createAll 过程中的超时等),并且还有一个回滚决策列表,应用程序必须能够回滚所有任务完成了。

我想要一些如何打破这种耦合代码的例子。


可能有用的伪代码:

class something
{  
    static result CreateAll(object1 obj1, object2 obj2 ...)
    {
        //Save to database obj1
        //...
        //Update to database obj1 
        //
        //NEW THREAD
       //Start a new thread with obj1, obj2 ...CreateAll
       //...          
     } 

    void CreateAllAsync()
    {
        //Type1 Save to database obj1
        //...
        //Type1 Update to database obj2

        //Type2 Call Web Service to create obj1 on the service (not async)

        while (state != null && now < times)
        {
            if (status == "OK")
            break;      
            else
            //Wait for X seconds
        }

        //Check status continue or general failure
        //Type1 Update to database obj2 and obj1

        //Type2 Call Web Service to create obj2 on the service (fire and forget)

        //Type3 Update Configuration File
        //Type1 Update to database obj2 and obj1
        //..   

    return;
}

//Then the UI takes the responsibility to check the status of result2

最佳答案

看看使用Polly对于似乎与您的伪代码一致的重试场景。此答案的末尾是文档中的示例。您可以执行各种重试场景,重试和等待等。例如,您可以多次重试一个完整的事务,或者多次重试一组幂等操作,然后在重试时编写补偿逻辑政策最终失败。

备忘录模式更适用于文字处理器(Ctrl-Z 和 Ctrl-Y)中的撤消-重做逻辑。

要查看的其他有用模式是简单队列、持久队列甚至服务总线,它们可为您提供最终一致性,而无需让用户等待一切成功完成。

// Retry three times, calling an action on each retry 
// with the current exception and retry count
Policy
    .Handle<DivideByZeroException>()
    .Retry(3, (exception, retryCount) =>
    {
        // do something 
    });

基于您的伪代码的示例可能如下所示:

static bool CreateAll(object1 obj1, object2 obj2)
{
     // Policy to retry 3 times, waiting 5 seconds between retries.
     var policy =
         Policy
              .Handle<SqlException>()
              .WaitAndRetry(3, count =>
              {
                 return TimeSpan.FromSeconds(5); 
              });

       policy.Execute(() => UpdateDatabase1(obj1));
       policy.Execute(() => UpdateDatabase2(obj2));
  }

关于c# - 在 C# 中为同步/异步任务添加重试/回滚机制的最佳方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37393828/

相关文章:

c# - 在 C# 中序列化和反序列化 Oracle.DataAccess.OracleException

.net - 向 .NET 程序集中的 ADODB 命令添加参数时出错

c# - 有谁知道有下划线的拼写检查库吗?

c# - 使用 .ashx 文件的 Web 表单的 URL 路由

c# - 有条件地转义特殊的 xml 字符

c# - 如何在 MessageBox 上显示 FARPROC 内存地址

c# - 不使用 Windows 窗体 (C#) 创建远程桌面客户端应用程序

c# - 将 youtube url 转换为 iframe 嵌入代码

asp.net - LINQ-to-SQL 查询不返回结果

javascript - 如何在 ASP.NET Web 表单中捕获 "F2" key