Filesystemwatcher with Samba on Linux

FileSystemWatcher with Samba on Linux

First of all, file system monitoring of remote shares is always going to be somewhat unreliable. You should not depend on your app getting all the events - in fact, I would suggest you provide a backup polling mechanism to check for changes that you may have missed. A refresh button in the GUI could be another option, depending on your app.

That said, your particular problem doesn't seem to be that uncommon. I googled around a bit and found these things:

  • Problem with FileSystemWatcher on 2003 server box - seems to be the same problem as you have, with a samba share and that "The specified server cannot perform the requested operation" error message.
  • SO Question regarding the same issue and one of the answers indicate that it worked for some customers and not for others

My guess is that this is a problem with certain versions (or configuration) of Samba combined with Windows. Are there anything in the Samba logs on the linux server that could point you towards the cause of the problem?

As an immediate workaround, I suggest you try these things:

  • Add a polling mechanism that ensures that you do get the folder changes even if the FSW breaks down
  • When the FSW breaks, try to "restart" it by creating a new one. You may also want to check if EnableRaisingEvents is set to false when you get the error - maybe you can just set it to true to start receiving events again.
  • (Grasping for straws here) try playing around with the internal buffer size in case that's the problem (I doubt it, but it's worth a shot)

Incorrect FileSystemWatcher behaviour with Samba

The "last accessed" time is inconsistently set by Windows programs: for instance, displaying the file properties context menu in Windows will reset this time. As you state, Windows Copy does not set the "last access" time, but a copy of a file on a Windows server using Samba does as it's Samba's internal drivers doing the copy.

Your only workaround, I fear, is to ignore the "last access" time using a filter in your FileSystemWatcher:

FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = "c:\yourpathhere";
watcher.NotifyFilter = NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;

or similar.

Why FileSystemWatcher doesn't work in Linux container watching Windows volume

Switching to PhysicalFileProvider did the job.
It seems to be a more portable implementation for file system watching strategies.

The current implementation of PhysicalFileProvider supports the DOTNET_USE_POLLING_FILE_WATCHER environment variable. I couldn't find any reference of it in FileSystemWatcher implementation.

using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Primitives;
using System;
using System.IO;

namespace fsw_bug_poc
{
class Program
{
private static PhysicalFileProvider _fileProvider;
private static IChangeToken _fileChangeToken;

static void Main(string[] args)
{
_fileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "."));
WatchForFileChanges();

Console.ReadKey(false);
}

private static void WatchForFileChanges()
{
_fileChangeToken = _fileProvider.Watch("*.*");
_fileChangeToken.RegisterChangeCallback(Notify, default);
}

private static void Notify(object state)
{
Console.WriteLine("File change detected");
WatchForFileChanges();
}
}
}

System.IO.FileSystemWatcher to monitor a network-server folder - Performance considerations

From a server load point of view, using the IO.FileSystemWatcher for remote change notifications in the scenario you describe is probably the most efficient method possible. It uses the FindFirstChangeNotification and ReadDirectoryChangesW Win32 API functions internally, which in turn communicate with the network redirector in an optimized way (assuming standard Windows networking: if a third-party redirector is used, and it doesn't support the required functionality, things won't work at all). The .NET wrapper also uses async I/O and everything, further assuring maximum efficiency.

The only problem with this solution is that it's not very reliable. Other than having to deal with network connections going away temporarily (which isn't too much of a problem, since IO.FileSystemWatcher will fire an error event in this case which you can handle), the underlying mechanism has certain fundamental limitations. From the MSDN documentation for the Win32 API functions:

  • ReadDirectoryChangesW fails with ERROR_INVALID_PARAMETER when the buffer length is greater than 64 KB and the application is monitoring a directory over the network. This is due to a packet size limitation with the underlying file sharing protocols

  • Notifications may not be returned when calling FindFirstChangeNotification for a remote file system

In other words: under high load (when you would need a large buffer) or, worse, under random unspecified circumstances, you may not get the notifications you expect. This is even an issue with local file system watchers, but it's much more of a problem over the network. Another question here on SO details the inherent reliability problems with the API in a bit more detail.

When using file system watchers, your application should be able to deal with these limitations. For example:

  • If the files you're looking for have sequence numbers, store the last sequence number you got notified about, so you can look for 'gaps' on future notifications and process the files for which you didn't get notified;

  • On receiving a notification, always do a full directory scan. This may sound really bad, but since the scan is event-driven, it's still much more efficient than dumb polling. Also, as long as you keep the total number of files in a single directory, as well as the number of directories to scan, under a thousand or so, the impact of this operation on performance should be pretty minimal anyway.

Setting up multiple listeners is something you should avoid as much as possible: if anything, this will make things even less reliable...

Anyway, if you absolutely have to use file system watchers, things can work OK as long as you're aware of the limitations, and don't expect 1:1 notification for every file modified/created.

So, if you have other options (essentially, having the process writing the files notify you in a non-file system based way: any regular RPC method will be an improvement...), those are definitely worth looking into from a reliability point of view.

FileSystemWatcher vs polling to watch for file changes

I have seen the file system watcher fail in production and test environments. I now consider it a convenience, but I do not consider it reliable. My pattern has been to watch for changes with the files system watcher, but poll occasionally to catch missing file changes.

Edit: If you have a UI, you can also give your user the ability to "refresh" for changes instead of polling. I would combine this with a file system watcher.

FileSystemWatcher to watch UNC path

I just tried this:

var _watcher = new FileSystemWatcher();
_watcher.Path = @"\\10.31.2.221\shared\";
_watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName;
_watcher.Filter = "*.txt";
_watcher.Created += new FileSystemEventHandler((x, y) =>Console.WriteLine("Created"));
_watcher.Error += new ErrorEventHandler( (x, y) =>Console.WriteLine("Error"));
_watcher.EnableRaisingEvents = true;
Console.ReadKey();

That works without problems, however i replicated your exception just when:

  • The running user doesn't have permissions to read the remote folder.
  • The remote folder doesn't exist.

Your problem surely is related with permissions, I think that the running user doesn't have the permissions needed.

Another thing that you can try is map the remote folder to one local.

Execute this in the cmd:

NET USE Z: \\server2\Secondary\temp\watch_folder /user:Domain\UserName Password

Then in your code:

_watcher.Path = @"Z:\";


Related Topics



Leave a reply



Submit