如何在超时的情况下一次又一次地执行方法,直到它成功完成

本文关键字:成功 方法 执行 超时 情况下 一次又一次 | 更新日期: 2023-09-27 18:09:24

我有asp.net应用程序。所有业务逻辑都在业务层。

下面是方法 的示例
public void DoSomething()
{
        PersonClass pc = new PersonClass();
        pc.CreatePerson();
        pc.AssignBasicTask();
        pc.ChangePersonsStatus();
        pc.CreateDefaultSettings();    
}

每隔一段时间发生一次,其中一个子方法可能超时,因此进程可能未完成。

我认为在这种情况下,确保所有步骤正确完成的方法是

public void DoSomething()
    {
            PersonClass pc = new PersonClass();
            var error = null;
            error =  pc.CreatePerson();
            if(error != timeout exception)                  
             error = pc.AssignBasicTask();
            else
              return to step above
            if(error != timeout exception)
              error = pc.ChangePersonsStatus();
            else
              return to step above
            if(error != timeout exception)
              error = pc.CreateDefaultSettings();
            else
              return to step above    
    }

但这只是一个想法,更确定的是这是一个正确的方式来处理这个

如何在超时的情况下一次又一次地执行方法,直到它成功完成

当然,这可以或多或少优雅地完成,使用不同的超时或放弃选项-但是实现您想要的一个简单方法是定义一个重试方法,它会不断重试一个操作,直到它成功:

public static class RetryUtility 
{
    public T RetryUntilSuccess<T>(Func<T> action) 
    {
        while(true) 
        {
            try 
            {
                return action();
            }
            catch 
            {
                // Swallowing exceptions is BAD, BAD, BAD. You should AT LEAST log it.
            }
        }
    }
    public void RetryUntilSuccess(Action action) 
    {
        // Trick to allow a void method being passed in without duplicating the implementation.
        RetryUntilSuccess(() => { action(); return true; });
    }
}

那么做

    RetryUtility.RetryUntilSuccess(() => pc.CreatePerson());
    RetryUtility.RetryUntilSuccess(() => pc.AssignBasicTask());
    RetryUtility.RetryUntilSuccess(() => pc.ChangePersonsStatus());
    RetryUtility.RetryUntilSuccess(() => pc.CreateDefaultSettings());   

我必须敦促您考虑如果方法一直失败该怎么办,您可能会创建一个无限循环-也许它应该在N次重试后放弃或以指数方式增加重试时间-您需要定义它,因为我们无法足够了解您的问题域来决定

你的伪代码已经非常接近正确了,有很多方法可以做到这一点,但这里是我的做法:

PersonClass pc = new PersonClass();
while(true)
   if(pc.CreatePerson())
      break;
while(true)
   if(pc.AssignBasicTask())
      break;

这假设您的方法返回true表示成功,返回false表示超时失败(并且可能是任何其他类型的失败的异常)。虽然我在这里没有这样做,但我强烈建议尝试计数,以确保它不会永远循环。

使用TransactionScope来确保所有内容作为一个单元执行。使用Transaction Scope

实现隐式事务

永远不要无限地重试超时操作,否则可能导致服务器挂起或无限循环,或者两者兼而有之。在退出之前,应该有一个可接受的重试次数的阈值。

示例:

using(TransactionScope scope = new TransactionScope())
{
   try
   {
      // Your code here
      // If no errors were thrown commit your transaction
      scope.Complete();          
   }
   catch
   {
      // Some error handling
   }
}