Search code examples
c#delayresetfilesystemwatcher

How to reset a Task.Delay() after a event fired?


I am trying to let some code fire after my FileSystemWatcher hasn't received any changes for more then 5 minutes.

My current approach is to call a await Task.Delay(); after a change, hoping the user is done by then. This obviously is not the way to go.

So my question: How to reset a Task.Delay() after a event fired?


Solution

  • You can't "reset" a Task.Delay, but you can reset a timer which makes it an ideal candidate to solve this problem.

    Here's an example:

        private System.Threading.Timer timer;
    
        public void Start()
        {
            timer = new System.Threading.Timer(_ => fireMyCode());
            restartTimer();
        }
    
        private void onFileChanged(object sender, EventArgs e)
        {
            restartTimer();
        }
    
        private void restartTimer()
        {
            timer.Change(TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5));
        }
    

    But you don't have to use timers, you can still use Task.Delay with an additional task: the idea is to wait on two tasks, the delay and waiting for the files to change (you can use TaskCompletionSource to "create" a task from an event). If the delay task completes first, fire your code.

    Here's an example:

        TaskCompletionSource<object> fileChanged = new TaskCompletionSource<object>();
    
        private void onFileChanged(object sender, EventArgs e)
        {
            fileChanged.TrySetResult(null);
        }
    
        private async Task endlessLoop()
        {
            while (true)
            {
                await handleFilesNotChanged();
            }
        }
    
        private async Task handleFilesNotChanged()
        {
            Task timeout = Task.Delay(TimeSpan.FromMinutes(5));
            Task waitForFile = fileChanged.Task;
    
            if (await Task.WhenAny(timeout, waitForFile) == timeout)
            {
                fireMyCode();
            }
            fileChanged = new TaskCompletionSource<object>();
        }