.NetCore - 网络驱动器上的 FileSystemWatcher,不安全代码 Win32 API 崩溃

.NetCore - FileSystemWatcher on a network drive, unsafe code Win32 API crash

我有一个小的 Dotnet 核心程序 (3.1.8),带有一些 FileWatchers。 他们查看 网络驱动器 上的文件夹。 在某些负载下(此处最多 200 - 250 个文件),程序会意外崩溃。 由于 Biztalk 应用程序,这些文件同时出现,由另一台服务器上的另一个进程移动,我认为它在这里不相关,但我想提一下。

filewatchers 初始化:

private void InitializeInnerFilewatcher(List<string> filters)
{
        _watcher = new FileSystemWatcher(WatchPath);
        _watcher.InternalBufferSize = 65536;
        if (filters.Count > 1)
        {
            _watcher.Filter = FILTER_ALL; // *.*
            _customFilters = filters;
        }
        else
            _watcher.Filter = filters.First();
        _watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName;
        _watcher.Changed += new FileSystemEventHandler(FileCreatedOrChanged);
        _watcher.Created += new FileSystemEventHandler(FileCreatedOrChanged);
        _watcher.Renamed += new RenamedEventHandler(FileRenamed);
        _watcher.Error += Watcher_Error;
        _watcher.EnableRaisingEvents = true;
}

这里是文件观察器触发的每个事件的“处理”部分:

private void TryHandle(FileSystemEventArgs arg)
{
        if (!File.Exists(arg.FullPath))
            return;

        if (!_customFilters.Any() || _customFilters.Any(x => PatternMatcher.MatchPattern(x, arg.Name)))
            _memoryCache.AddOrGetExisting(arg.FullPath, arg, _cacheItemPolicy);
 }

我试图避免对触发的文件系统事件进行任何实际处理,所以我将文件路径推送到 memoryCache 中,然后将其发送到 ServiceBus 队列以供任何使用者处理文件。

所有这些东西似乎一整天都工作得很好,没有高CPU一整天没有高内存。我们已经在 ApplicationInsights 中记录了所有应用程序指标。

这是一个 'real' 崩溃,所以我们没有任何日志,只有事件查看器中的不良事件和转储文件。

事件查看器: Faultinq module name: coreclr.dll, version: 470020.41105, time stamp: Ox5f3397ec

我们可以看到,感谢 dotnet-dump,转储文件中捕获的错误:

> clrstack
OS Thread Id: 0xfd4c (27)
        Child SP               IP Call Site
00000022D55BE150 00007ffccc46789f [FaultingExceptionFrame: 00000022d55be150]
00000022D55BE650 00007FFC6D7A49D4 System.IO.FileSystemWatcher.ParseEventBufferAndNotifyForEach(Byte[]) [/_/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.Win32.cs @ 249]
00000022D55BE6F0 00007FFC6D7A48E6 System.IO.FileSystemWatcher.ReadDirectoryChangesCallback(UInt32, UInt32, System.Threading.NativeOverlapped*) [/_/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.Win32.cs @ 242]
00000022D55BE750 00007FFC6D6F189C System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) [/_/src/System.Private.CoreLib/shared/System/Threading/ExecutionContext.cs @ 201]
00000022D55BE7C0 00007FFC6D7359B5 System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32, UInt32, System.Threading.NativeOverlapped*) [/_/src/System.Private.CoreLib/src/System/Threading/Overlapped.cs @ 59]
00000022D55BE8F0 00007ffccc336ba3 [GCFrame: 00000022d55be8f0]
00000022D55BEAB0 00007ffccc336ba3 [DebuggerU2MCatchHandlerFrame: 00000022d55beab0]
> pe
Exception object: 000001e580001198
Exception type:   System.ExecutionEngineException
Message:          <none>
InnerException:   <none>
StackTrace (generated):
<none>
StackTraceString: <none>
HResult: 80131506

如您所见,错误似乎直接发生在 Win32 API 中的 FileSystemWatcher 上。 我无法重现它,它只发生在我们的生产环境中,所以无需告诉你我处于“紧急模式”。

WinDbg 可能更详细一些

只是一个快速更新,因为我仍在修复它的路上。

我创建了一个 MS 支持问题。 经过多次尝试,我们才成功地重现了它。我们不得不“玩”网络并模拟一些“干扰”。 似乎 FileSystemWatcher 事件没有按应有的方式发送(它是通过 TCP 协议发送的,SMB 方式)。 我们的团队仍在努力寻找它是如何发生的..

MS 同意,无论是否存在真正的网络问题,这都不应该使某些不安全代码中的 FileSystemWatcher 崩溃。 所以,他们只是做了一个 PR 来增加一些安全性。

我仍在关注 PR,但它应该在 .Net 5 中修复并在 .Net Core 3.1(.9) 中向后移植。

感谢您的帮助。

此问题已在 master (6.0) and backported to 5.0 and 3.1 中修复。