Reputation: 5389
I have an application that has a main thread that waits for an event (receiving a file in the directory, for example) and Post that file to an API. This part is working fine.
On the other hand, due to some reasons, it's possible that the main thread misses out some files. So, I have setup a background thread to run throughout application lifetime cleaning up those missed files as shown below:
public virtual void MissedFileHandler()
{
if (_missedFileHandlerThread == null || !_missedFileHandlerThread.IsAlive)
{
_missedFileHandlerThread = new Thread(new ThreadStart(ClearMissedFiles));
_missedFileHandlerThread.IsBackground = true;
_missedFileHandlerThread.Start();
}
}
protected virtual void ClearMissedFiles()
{
while (true)
{
string[] missedFiles = new string[] { };
missedFiles = Directory.GetFiles(ConfigurationHelper.applicationRootDirectory, "*.txt", SearchOption.TopDirectoryOnly);
Parallel.ForEach(missedFiless, (currentMissedFile) =>
{
bool isFileInUse = true;
isFileInUse = FileHelper.CheckIfFileInUse(filesInUseCollection, currentMissedFile)
if (!isFileInUse)
{
bool isHttpTransferSuccess = false;
isHttpTransferSuccess = FileHelper.SendFileToApi(userid, currentMissedFile);
if (isHttpTransferSuccess)
{
File.Delete(currentMissedFile);
}
}
});
Thread.Sleep(1000);
}
}
Please note that running this as a Windows service or a scheduler is not an option for some other reasons. So, I do need a background worker to clean up missed files periodically. I checked out Timer
and WaitHandles
but not very sure how I can implement the following using those.
The way the two processes (main even handler for new files and the background cleaner is invoked are, in the main application thread I will instantiate the class and invoke the methods at application startup. It's the Thread.Sleep()
and the while (true)
that is bothering me and am looking for a better approach. Thanks.
Upvotes: 0
Views: 80
Reputation: 117154
Try using Microsoft's Reactive Framework. Then you can do this:
IObservable<Unit> fileChanges =
Observable
.Using(() =>
{
var fsw = new FileSystemWatcher();
fsw.Path = path;
fsw.EnableRaisingEvents = true;
return fsw;
}, fsw =>
Observable
.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
h => fsw.Changed += h,
h => fsw.Changed -= h))
.Select(ep => Unit.Default);
IObservable<Unit> periodically =
Observable
.Interval(TimeSpan.FromSeconds(30.0))
.Select(x => Unit.Default);
IObservable<string> clearMissedFiles =
fileChanges
.Merge(periodically)
.SelectMany(u => Directory.GetFiles(ConfigurationHelper.applicationRootDirectory, "*.txt", SearchOption.TopDirectoryOnly))
.Where(f => !FileHelper.CheckIfFileInUse(filesInUseCollection, f))
.SelectMany(f => Observable.Start(() => FileHelper.SendFileToApi(userid, f)), (f, s) => new { file = f, success = s })
.Where(x => x.success)
.Select(x => x.file);
IDisposable subscription =
clearMissedFiles
.Subscribe(f => File.Delete(f));
This watches the file system and check periodically. And calls the API in parallel and it doesn't cause the O/S grief with trying to delete multiple files at once.
Just call subscription.Dispose()
to clean up before exiting.
NuGet "System.Reactive" for the bits and then reference using System.Reactive.Linq
for the extensions to show.
Upvotes: 1
Reputation: 1184
You can use a file watcher to detect new files in that directory.
private void watch()
{
FileSystemWatcher watcher = new FileSystemWatcher();
// Set your path with this
watcher.Path = path;
// Subscribe to event
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.EnableRaisingEvents = true;
}
Upvotes: 3