哪个是在C#中添加同步/异步任务的重试/回滚机制的最佳方式? [英] Which is the best way to add a retry/rollback mechanism for sync/async tasks in C#?

查看:269
本文介绍了哪个是在C#中添加同步/异步任务的重试/回滚机制的最佳方式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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



2)开始一个新线程



3)Result1 =调用一个soap服务,使用超时阈值检查状态并在x分钟后继续(状态现在可以,并不意味着失败)



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



5)result2 =调用肥皂服务(在火中,忘记)



6)更新配置文件(实际上是从result1获取的)



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



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





  • 类型2:服务通信/事务

  • Type3:配置文件I / O事务



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



我发现C#中的美图设计模式 OR 命令模式可能有助于此目的。我还发现了msdn 重试模式描述有趣。我不是真的知道,我希望有人带我去最安全,最好的决定...



你能否建议我这个案子最好的方法来保持现有的实现和流程,但将其包装在一般和抽象的重试/回滚/任务列表实现中?



最终实现必须能够在每种情况下重试(无论任务或一般的失败,例如在整个一般的createAll进程中的超时等等),还有一个回滚决定列表,应用程序必须能够回滚所有完成的任务。



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






可能有用的PseudoCode:

  class something 
{
static result CreateAll(object1 obj1,object2 obj2 ...)
{
//保存到数据库obj1
// ...
//更新到数据库obj1
//
// NEW THREAD
/ /启动一个新的线程与obj1,obj2 ... CreateAll
// ...
}

void CreateAllAsync()
{
// Type1保存到数据库obj1
// ...
// Type1更新到数据库obj2

// Type2调用Web服务在服务上创建obj1(不是异步)

while(state!= null&&&现在< times)
{
if(status ==OK)
break;
else
//等待X秒
}

//检查状态继续或一般故障
// Type1更新到数据库obj2和obj1

// Type2调用Web服务在服务上创建obj2(fire and forget)

// Type3更新配置文件
// Type1更新到数据库obj2和obj1
// ..

return;
}

//然后UI负责检查result2的状态


解决方案

使用 Polly 查看对于重试场景,似乎与您的伪代码很好地对齐。这个答案的结尾是文档中的一个例子。您可以进行各种重试场景,重试和等待等等。例如,您可以重试一次完整的事务,或者重试一组幂等动作次数,然后在/重试时写入补偿逻辑政策终于失败了。



在文字处理器(Ctrl-Z和Ctrl-Y)中您可以找到一个纪念图案更多用于撤消重做逻辑。



其他有用的模式是一个简单的队列,一个持久队列甚至是一个服务总线,可以给您最终的一致性,而无需让用户等待所有的事情成功完成。

  //重试三次,在每次重试
//时调用一个动作,使用当前的异常并重试计数
策略
.Handle< DivideByZeroException>()
.Retry(3,(exception,retryCount)=>
{
// do something
} );

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

  static bool CreateAll(object1 obj1,object2 obj2)
{
//重试次数3次,重试次数等待5秒。
var policy =
策略
.Handle< SqlException>()
.WaitAndRetry(3,count =>
{
return TimeSpan.FromSeconds 5);
});

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


Imagine of a WebForms application where there is a main method named CreateAll(). I can describe the process of the method tasks step by step as follows:

1) Stores to database (Update/Create Db items 3-4 times)

2) Starts a new thread

3) Result1 = Calls a soap service, and by using a timeout threshold it checks the status and after x minutes.The it continues (status now is OK and it isn't means failure)

4) Stores to database (Update/Create Db items 3-4 times)

5) result2 = Calls a soap service (In a fire and forget way)

6) Updates a configuration file (that is taken actually from result1)

7) By using callback requests it checks every x secs at front part the state of the result2 and the UI shows a progress bar.If the process is finished (100%) it means success

I am considering that all of them are tasks that can be grouped by their type.Basically the several types of actions are :

  • Type1: DB transaction
  • Type2: Service communication/transaction
  • Type3: Config file I/O transactions

I want to add a rollback/retry mechanism to the existing implementation and to use a task oriented architecture and refactor existing legacy code.

I found that something like Memento Design Pattern OR Command Pattern in C# could help for this purpose.I also found the msdn Retry Pattern description interesting. I don't realy know and I want someone to lead me to the safest and best decision...

Can you suggest me the best way for this case to keep the existing implementation and the flow but wrapping it in a general and abstract retry/rollback/tasklist implementation ?

The final implementation must be able to retry in every case (whatever task or general failure such as timeout etc throughout the general createAll process) and also there would be a rollback decision list where the app must be able to rollback all the tasks that was accomplished.

I want some examples how to break this coupled code.


PseudoCode that might be helpful:

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

解决方案

Look at using Polly for retry scenarios which seems to align well with your Pseudo code. At the end of this answer is a sample from the documentation. You can do all sorts of retry scenarios, retry and waits etc. For example, you could retry a complete transaction a number of times, or alternatively retry a set of idempotent actions a number of times and then write compensation logic if/when the retry policy finally fails.

A memento patterns is more for undo-redo logic that you would find in a word processor (Ctrl-Z and Ctrl-Y).

Other helpful patterns to look at is a simple queue, a persistent queue or even a service bus to give you eventual consistency without having to have the user wait for everything to complete successfully.

// 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 
    });

A sample based on your Pseudo-Code may look as follows:

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#中添加同步/异步任务的重试/回滚机制的最佳方式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆