0

I'm using FileSystemWatcher to upload files to an Azure Blob and I ran into a problem when a bunch of files were created at the same time, resulting in connection issues as every file gets a new connection to the Azure storage account.

I followed the following to group multiple files created at about the same time and execute them inside one storage account connection: Using FileSystemWatcher with multiple files

Of course I changed it a bit as I need multiple actions to be executed for each folder that's being watched.

This creates and starts the FileSystemWatcher.

        private void StartFileSystemWatcher(FolderSettings folder) {
            DirectoryInfo dir = new DirectoryInfo(folder.Path);

            // Checks whether the folder is enabled and
            // also the directory is a valid location
            if (folder.Enabled && dir.Exists) {
                FileSystemWatcher fileSWatch = new FileSystemWatcher();
                fileSWatch.Filter = folder.Filter;
                fileSWatch.Path = folder.Path;
                List<int> actionToExecute = folder.Actions;
                fileSWatch.IncludeSubdirectories = folder.Recursive;

                // Subscribe to notify filters
                fileSWatch.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;

                // Associate the event that will be triggered when a new file
                // is added to the monitored folder, using a lambda expression                   
                fileSWatch.Created += (senderObj, fileSysArgs) => FileSWatch_Created(senderObj, fileSysArgs, folder);
                fileSWatch.Error += (senderObj, fileSysArgs) => FileSWatch_Error(senderObj, fileSysArgs, folder);

                // Begin watching
                fileSWatch.EnableRaisingEvents = true;
            }
            else if (!dir.Exists) {
                Console.WriteLine(string.Format("Directory '{0}' does not exist!", dir.FullName));
            }
        }

There's a 'FolderSettings' object for each folder that's being monitored. It also contains the following:

  • ReaderWriterLockSlim rwlock
  • System.Timers.Timer ProcessTimer
  • List FilePaths
        private void FileSWatch_Created(object sender, FileSystemEventArgs e, FolderSettings folder) {
            // Set up timer to group events
            try {
                folder.rwlock.EnterWriteLock();
                folder.FilePaths.Add(e.FullPath);

                if (folder.ProcessTimer == null) {
                    // First file, start timer
                    folder.ProcessTimer = new System.Timers.Timer(2000);
                    folder.ProcessTimer.Elapsed += (senderObj, elapsedEventArgs) => ProcessQueue(senderObj, elapsedEventArgs, folder);
                    
                    folder.ProcessTimer.Start();
                }
                else {
                    // Subsequent file, reset timer
                    folder.ProcessTimer.Stop();
                    folder.ProcessTimer.Start();
                }
            }
            finally {
                folder.rwlock.ExitWriteLock();
            }
        }

The error is being thrown in the below code, even with only one action defined and one file that needs to be acted on:

'The read lock is being released without being held.'

        private async void ProcessQueue(object sender, ElapsedEventArgs e, FolderSettings folder) {
            List<Task> actionTasks = new List<Task>();
            folder.rwlock.EnterReadLock();

            try {
                List<FolderActions> fActs = listActions.Where(a => folder.Actions.Contains(a.Id)).ToList();

                fActs.ForEach(a => actionTasks.Add(a.Execute(folder.FilePaths)));
                await Task.WhenAll(actionTasks);

                folder.FilePaths.Clear();
            }
            finally {
                if (folder.ProcessTimer != null) {
                    folder.ProcessTimer.Stop();
                    folder.ProcessTimer.Dispose();
                    folder.ProcessTimer = null;
                }

                folder.rwlock.ExitReadLock();
            }
        }

Any idea how to fix?

Hofa
  • 51
  • 6
  • 1
    `ReaderWriterLockSlim` doesn't work with `async` as it depends on the correct thread releasing the lock. You need to use `SemaphoreSlim` or other – Charlieface Sep 02 '22 at 14:29

0 Answers0