Недавно мы посетили кластерный файловый сервер CSVFS. У меня есть наблюдатель за файлами, который отслеживает 4 каталога для событий OnCreated
и OnRenamed
, но всякий раз, когда узел изменяется, это вызывает переполнение буфера с ошибкой
Слишком много изменений одновременно в каталоге
Наблюдатели автоматически перезапускаются, и процесс продолжает работать, но начинает писать ошибки при запуске событий OnCreated
/OnRenamed
.
Не удается получить доступ к ликвидированному объекту.
Имя объекта: 'FileSystemWatcher'.
at System.IO.FileSystemWatcher.StartRaisingEvents()
at System.IO.FileSystemWatcher.set_EnableRaisingEvents(логическое значение)
В приведенном ниже методе 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) { }
}