我可以使用自定义属性类将方法修饰为自动重试

时间:2016-04-19 16:56:41

标签: c# .net

我有一个简单的c#方法,如果在中间抛出任何异常,我想在一段时间后(即2分钟)重新运行/继续该方法,直到它完成。例如,如果在for循环中发生任何异常,我想在一些可配置的时间后运行此方法,而不是抛出异常

  public void Process(List<string> msg)
  {
      foreach(var m in msg) {  }
  }

通过装饰像这样的东西

 [ReRun(Maxtime =5, TimeIntervalInSec=600)]
  public void Process(List<string> msg)
   {
      foreach(var m in msg) {  }
   }

可以作为Separate类完成,并作为属性插入此方法吗?

2 个答案:

答案 0 :(得分:1)

您必须编写 lot 更多(复杂)代码,以使任何内容按照您的布局方式运行。仅使用超时调用辅助方法会更加简单。

你可能应该将它作为一个单独的线程运行,或者你将要&#34;挂起&#34;你在&#34;睡眠期间的主要处理线程&#34;周期。

总的来说,我会质疑你是否需要重新考虑整个方法论。

public void Process(List<string> msg)
{
    bool permfail = false;
    bool complete = false;
    int runCount = 0;
    while (!complete && !permfail)
    {
        try
        {
            AttemptProcess(msg);
            complete = true;

        }
        catch
        {
            if (runCount++ > 10)
                permfail = true;
            else
                System.Threading.Thread.Sleep(new TimeSpan(0, 2, 0));
        }
    }
}
void AttemptProcess(List<string> msg)
{
    // Do whatever processing here
}   

答案 1 :(得分:1)

如果抛出异常,我会修改调用者再次调用该方法,而不是这样做。单一责任原则表明,管理如何调用它或调用者抛出异常时所做的事情不是一个类的工作。 (但你已经看到了,因为你避免将它直接放在方法中。)

我写了这个并做了一些快速的单元测试。 (我在命名方面很糟糕。)用法是

var execution = new RetryExecution<int>(() => SomeFunctionThatReturnsAnInt());
var result = execution.Execute(2); //specifies maximum number of attempts.

它调用给定方法 n 次并返回值或抛出最后一个异常。 Exceptions属性返回任何未被删除的异常。

public class RetryExecution<T>
{
    private readonly Func<T> _function;
    private List<Exception> _exceptions = new List<Exception>();

    public RetryExecution(Expression<Func<T>> expression )
    {
        _function = expression.Compile();
    }

    public Exception[] Exceptions { get { return _exceptions.ToArray(); } }

    public T Execute(int maxAttempts)
    {
        var attempts = 0;
        while (attempts < maxAttempts)
        {
            attempts++;
            try
            {
                return _function.Invoke();
            }
            catch (Exception ex)
            {
                if (attempts >= maxAttempts) throw;
                _exceptions.Add(ex);
            }
        }
        return default(T);//Not reachable, but compiler needs it.
    }
}