Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Given the program:

using System;
using System.IO;

namespace fsw_bug_poc
{
    class Program
    {
        private static FileSystemWatcher _fileSystemWatcher;

        static void Main(string[] args)
        {
            _fileSystemWatcher = new FileSystemWatcher("Watched", "*.*");
            _fileSystemWatcher.Changed += Notify;
            _fileSystemWatcher.Created += Notify;
            _fileSystemWatcher.Deleted += Notify;
            _fileSystemWatcher.Renamed += Notify;
            _fileSystemWatcher.IncludeSubdirectories = true;
            _fileSystemWatcher.EnableRaisingEvents = true;

            Console.ReadKey(false);
        }

        private static void Notify(object sender, FileSystemEventArgs e)
        {
            Console.WriteLine($"{e.FullPath} {e.ChangeType}");
        }
    }
}

The Dockerfile:

FROM mcr.microsoft.com/dotnet/core/runtime:2.2-stretch-slim AS base
WORKDIR /app

FROM mcr.microsoft.com/dotnet/core/sdk:2.2-stretch AS build
WORKDIR /src
COPY ["fsw-bug-poc.csproj", ""]
RUN dotnet restore "fsw-bug-poc.csproj"
COPY . .
WORKDIR "/src/"
RUN dotnet build "fsw-bug-poc.csproj" -c Release -o /app

FROM build AS publish
RUN dotnet publish "fsw-bug-poc.csproj" -c Release -o /app

FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENV DOTNET_USE_POLLING_FILE_WATCHER=true
RUN mkdir -p /app/Watched
VOLUME /app/Watched
ENTRYPOINT ["dotnet", "fsw-bug-poc.dll"]

According to this link adding ENV DOTNET_USE_POLLING_FILE_WATCHER=true to the Dockerfile fixes the FileSystemWatcher not working inside the container.

Even with this fix, FileSystemWatcher will not work when running a Linux container on Windows and mounting a shared driver to a volume:

docker build -t fsw-bug-poc .
docker run -it --rm -v C:\Shared:/app/Watched fsw-bug-poc

Modifying a file inside the container:

running touch inside the container

touch working inside container

Modifying files in the shared volume folder:

modifying files in the shared folder

Nothing happens!!

nothing happens when modifying shared folder on windows

Can someone explain what is going on? The FileSystemWatcher is using a polling strategy, so it should work the same way, shouldn't it?

like image 742
natenho Avatar asked Jul 14 '19 04:07

natenho


People also ask

Does FileSystemWatcher work on Linux?

The Linux implementation of FileSystemWatcher creates a new thread with its own inotify instance for every directory that's watched.

What is FileSystemWatcher?

Use FileSystemWatcher to watch for changes in a specified directory. You can watch for changes in files and subdirectories of the specified directory. You can create a component to watch files on a local computer, a network drive, or a remote computer.

How do I stop FileSystemWatcher?

To stop the watcher from reporting changes then set its EnableRaisingEvents property to False. If you've finished with it then Dispose it. Your problem is that you haven't retained a reference to any of the FileSystemWatchers you've created.


1 Answers

Switching to PhysicalFileProvider.Watch 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();
        }
    }
}
like image 140
natenho Avatar answered Sep 27 '22 20:09

natenho