c# - 处理更改节点的最佳方法? -C#文件监视程序和群集文件服务器

标签 c# error-handling fileserver file-watcher

我们最近去了CSVFS群集文件服务器。我有一个文件监视程序,它正在监视4个目录中的OnCreatedOnRenamed事件,但是只要节点发生更改,就会导致缓冲区溢出并显示错误

Too many changes at once in directory



监视程序将自动重新启动,并且该过程继续进行,但是在触发OnCreated/OnRenamed事件时开始写入错误。

Cannot access a disposed object.
Object name: 'FileSystemWatcher'.
at System.IO.FileSystemWatcher.StartRaisingEvents()
at System.IO.FileSystemWatcher.set_EnableRaisingEvents(Boolean value)



在下面的OnCreated方法中,如果要执行此操作,是否可以使用?
watchit = source as FileSystemWatcher;

我实际上并没有将新创建的FileSystemWatcher分配给其他任何地方的watchit

更多详情/代码

最初启动进程时,将通过foreach循环创建观察者。 FileChange只是一种确定更改类型,进行一些工作然后触发更改类型正确操作的方法。
foreach (string subDir in subDirs)
{
    string localFolder = $"{subDir}";

    watchit = new FileSystemWatcher
                    {
                        Path = localFolder,
                        EnableRaisingEvents = true,
                        IncludeSubdirectories = false,
                        NotifyFilter = NotifyFilters.FileName | NotifyFilters.CreationTime,
                        Filter = watchFor,
                        InternalBufferSize = 65536,
                        SynchronizingObject = null //,
                    };

    watchit.Changed += FileChange;
    watchit.Created += FileChange;
    watchit.Deleted += FileChange;
    watchit.Renamed += OnRename;
    watchit.Error += OnError;
    watchit.EnableRaisingEvents = true;

    watchers.Add(watchit);

    Console.WriteLine($"watching {subDir} for {watchFor}");
}
watchit是全局设置的静态FileSystemWatcher
private static async Task<int> OnCreated<T>(object source, FileSystemEventArgs e, string ext)
{
    int insertResult = 0;

    try
    {
        watchit.EnableRaisingEvents = false;
        EventLogWriter.WriteEntry("File: " + e.FullPath + " " + e.ChangeType);
        Console.WriteLine("File: " + e.FullPath + " " + e.ChangeType + " " + DateTime.Now);
        insertResult = await FileHandler.FileHandlers().ConfigureAwait(false);
        watchit.EnableRaisingEvents = true;
        // if (insertResult > 0) File.Delete(e.FullPath);
    }
    catch (Exception ex)
    {
        Logger.Trace($"{ex.Message} {ex.StackTrace} {ex.InnerException}");
        EventLogWriter.WriteEntry($"{ex.Message} {ex.StackTrace} {ex.InnerException}",
        EventLogEntryType.Error);
        watchit.EnableRaisingEvents = true;
    }
    finally
    {
        watchit.EnableRaisingEvents = true;
    }

    return insertResult;
}

这些是我的错误处理方法。
private static void OnError(object source, ErrorEventArgs e)
{
    if (e.GetException().GetType() == typeof(InternalBufferOverflowException))
    {
        EventLogWriter.WriteEntry($"Error: File System Watcher internal buffer overflow at {DateTime.Now}", EventLogEntryType.Warning);
    }
    else
    {
        EventLogWriter.WriteEntry($"Error: Watched directory not accessible at {DateTime.Now}", EventLogEntryType.Warning);
    }

    MailSend.SendUploadEmail($"ASSIST NOTES: {e.GetException().Message}", "The notes service had a failure and should be restarted.", "admins", e.GetException(), MailPriority.High);
    NotAccessibleError(source as FileSystemWatcher, e);
}

    /// <summary>
    /// triggered on accessible error.
    /// </summary>
    /// <param name="source">The source.</param>
    /// <param name="e">The <see cref="ErrorEventArgs"/> instance containing the event data.</param>
    private static void NotAccessibleError(FileSystemWatcher source, ErrorEventArgs e)
        {
        EventLogWriter.WriteEntry($"Not Accessible issue. {e.GetException().Message}" + DateTime.Now.ToString("HH:mm:ss"));

        int iMaxAttempts = 120;
        int iTimeOut = 30000;
        int i = 0;
        string watchPath = source.Path;
        string watchFilter = source.Filter;
        int dirExists = 0;
        try
            {
            dirExists = Directory.GetFiles(watchPath).Length;
            }
        catch (Exception) { }
        try
            {
            while (dirExists == 0 && i < iMaxAttempts)
                {
                i += 1;
                try
                    {
                    source.EnableRaisingEvents = false;
                    if (!Directory.Exists(source.Path))
                        {
                        EventLogWriter.WriteEntry(
                            "Directory Inaccessible " + source.Path + " at " +
                            DateTime.Now.ToString("HH:mm:ss"));
                        Console.WriteLine(
                            "Directory Inaccessible " + source.Path + " at " +
                            DateTime.Now.ToString("HH:mm:ss"));
                        System.Threading.Thread.Sleep(iTimeOut);
                        }
                    else
                        {
                        // ReInitialize the Component
                        source.Dispose();
                        source = null;
                        source = new System.IO.FileSystemWatcher();
                        ((System.ComponentModel.ISupportInitialize)(source)).BeginInit();
                        source.EnableRaisingEvents = true;
                        source.Filter = watchFilter;
                        source.Path = watchPath;
                        source.NotifyFilter = NotifyFilters.FileName | NotifyFilters.CreationTime;
                        source.Created += FileChange;
                        source.Renamed += OnRename;
                        source.Error += new ErrorEventHandler(OnError);
                        ((System.ComponentModel.ISupportInitialize)(source)).EndInit();
                        EventLogWriter.WriteEntry(
                            $"Restarting watcher {watchPath} at " + DateTime.Now.ToString("HH:mm:ss"));
                        dirExists = 1;
                        }
                    }
                catch (Exception error)
                    {
                    EventLogWriter.WriteEntry($"Error trying Restart Service {watchPath} " + error.StackTrace +
                                               " at " + DateTime.Now.ToString("HH:mm:ss"));
                    source.EnableRaisingEvents = false;
                    System.Threading.Thread.Sleep(iTimeOut);
                    }
                }
            //Starts a new version of this console appp if retries exceeded
            //Exits current process
            var runTime = DateTime.UtcNow - Process.GetCurrentProcess().StartTime.ToUniversalTime();
            if (i >= 120 && runTime > TimeSpan.Parse("0:00:30"))
                {
                Process.Start(Assembly.GetExecutingAssembly().Location);
                Environment.Exit(666);
                }
            }
        catch (Exception erw) { }
        }

最佳答案

您正在尝试在FileSystemWatcher事件中做太多工作。监视程序由非托管缓冲区支持,需要尽快清空这些缓冲区以跟上更改。

理想情况下,所有事件应该做的是读取一些非常基础的数据,例如更改的路径和更改的类型,然后将其放入队列以在另一个线程上进行处理。另一个线程可以完成繁重的工作,因为它不会阻塞非托管的更改缓冲区。

关于c# - 处理更改节点的最佳方法? -C#文件监视程序和群集文件服务器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47353180/

相关文章:

c# - WCF 模拟的目的

java - 为什么有些时候Java无法捕获错误?

asp.net-web-api - 如何在Web API 2应用程序中全局捕获和记录所有异常/错误?

swift - “ fatal error :在展开可选值时意外发现nil”是什么意思?

http - 文件服务器不会提供超过 32 KB 的文件

windows - 已达到网络 BIOS 命令限制

c# linq - 基于集合的操作

c# - 获取 OleDbCommandBuilder 生成的 SQL 命令

c# - 将参数或参数传递给 Uwp 中的后台任务

javascript - 使用 Javascript 将 div 内容作为图像附加到 formData