挂起任务模式:稍后再试

本文关键字:任务 模式 挂起 | 更新日期: 2023-09-27 18:26:07

我使用了几个FileSystemWatcher对象来监视几个目录。

当我做复制&在一个被监视的文件夹上粘贴多个文件的操作,FileSystemWatcher为我捕获的每个新创建的文件引发一个Created事件。

我使用并发性为n的线程池,以便将作业排入队列并控制我想要在it上工作的线程数量(我可以一次创建200个文件,但我只希望有4个线程在it"表示计算校验和:

private byte[] calculateChecksum(string frl)
{
    byte[] checksum = null;
    FileStream stream = null;
    try
    {
        stream = File.Open(frl, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
        MD5 md5 = MD5.Create();
        checksum = md5.ComputeHash(stream);
    }
    finally
    {
        stream.Close();
    }
    return checksum;
}

问题是,有时线程在处理该作业(calculateChecksum方法)时,会尝试访问文件,但有时文件正在使用中(我支持SO)。

我想设置一个解决方案来解决这个问题,告诉我:"稍后再试"。

一种解决方案是,将作业再次放入线程池中。问题是我不知道以后如何告诉。我相信这很重要,因为我不希望它呼吸和休息很短时间,然后再试一次。

例如:

  • 在监视文件夹上创建了新文件
  • FileSystemWatcher引发一个事件
  • 我将作业排入线程池
  • 作业崩溃,因为我想访问的文件正被另一个进程使用
  • 再次将作业排队,等待60秒重试
  • 60秒后,作业再次崩溃,我希望作业再次排队并等待300秒
  • 300秒后,它再次尝试,并且能够正确计算校验和

我不希望这样:等待300秒意味着线程池中的一个线程正忙。它不允许调度其他排队的作业。

我不知道我是否清楚。任何想法

挂起任务模式:稍后再试

基本上你想要一个带定时器的重试模式。

你可以用Polly:轻松做到这一点

// Retry, waiting a specified duration between each retry
Policy
  .Handle<DivideByZeroException>()
  .WaitAndRetry(new[]
  {
    TimeSpan.FromSeconds(1),
    TimeSpan.FromSeconds(2),
    TimeSpan.FromSeconds(3)
  });

https://github.com/App-vNext/Polly

或者像下面没有polly的一样:

https://stackoverflow.com/a/1563234/1384539