У меня есть простой метод С #. Если в середине возникнет какое-либо исключение, я хочу повторно запустить / продолжить метод через некоторое время (например, 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) {  }
   }

Можно ли сделать это как отдельный класс и подключить как атрибут к этому методу?

-1
Mathiyazhagan 19 Апр 2016 в 19:56

2 ответа

Лучший ответ

Вместо этого я бы изменил вызывающего абонента, чтобы он снова вызвал метод, если он вызовет исключение. Принцип единой ответственности предполагает, что задача класса - не управлять тем, как он вызывается или что делает вызывающий объект, если он генерирует исключение. (Но вы уже видели это, потому что избегали помещать это непосредственно в метод.)

Я написал это и провел несколько быстрых модульных тестов. (Я не умею называть вещи.)

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.
    }
}
1
Scott Hannen 19 Апр 2016 в 17:51

Вы должны написать много более (сложного) кода, чтобы все работало так, как вы изложили. Будет намного проще просто вызвать вторичный метод с таймаутом.

И вам, вероятно, следует запустить это как отдельный поток, или вы собираетесь «повесить» свой основной поток обработки на время «спящего» периода.

В целом, я бы поставил под вопрос, нужно ли вам полностью переосмыслить свою методологию.

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
Mike U 19 Апр 2016 в 17:24