Skip to content

Instantly share code, notes, and snippets.

@dlyz
Last active May 25, 2020 11:35
Show Gist options
  • Save dlyz/e971d79b37c3450ec9ef7f40f824cdde to your computer and use it in GitHub Desktop.
Save dlyz/e971d79b37c3450ec9ef7f40f824cdde to your computer and use it in GitHub Desktop.
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.FileProviders.Physical;
using Microsoft.Extensions.Primitives;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
namespace FileWatcherRepro
{
class Program
{
static async Task Main(string[] args)
{
var dir = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
// this triggers System.ArgumentOutOfRangeException
{
var triggerDir = Path.Combine(dir, "a");
Directory.CreateDirectory(triggerDir);
File.WriteAllText(Path.Combine(triggerDir, "file.txt"), "");
}
var cts = new CancellationTokenSource();
var tasks = new List<Task>();
if (args.Contains("--fsloader"))
{
tasks.Add(RunFSLoader());
}
if (args.Contains("--watcher"))
{
tasks.Add(RunFSWatcher());
}
if (tasks.Count == 0)
{
tasks.Add(RunFSLoader());
tasks.Add(RunFSWatcher());
}
var t = Task.WhenAll(tasks);
Console.WriteLine("STARTED");
Console.ReadKey();
cts.Cancel();
await t;
async Task RunFSLoader()
{
Console.WriteLine("Starting FSLoader");
try
{
await LoadFileSystem(dir, 2, 1, cts.Token);
}
catch (Exception ex)
{
Console.WriteLine("FSLoader failed: {0}", ex);
}
}
async Task RunFSWatcher()
{
Console.WriteLine("Starting FSWatcher");
try
{
await WatchFile(dir, 1, cts.Token);
//await WatchFileProv(dir, cts.Token);
}
catch (Exception ex)
{
Console.WriteLine("FSWatcher failed: {0}", ex);
}
}
}
static Task LoadFileSystem(string root, int threads, int files, CancellationToken cancellationToken)
{
var dir = Path.Combine(root, "inner");
if (Directory.Exists(dir))
{
Directory.Delete(dir, recursive: true);
}
return Spawn(threads, (i, ct) => Run(Path.Combine(dir, $"pref{i}"), files, ct), cancellationToken);
static async Task Run(string dir, int files, CancellationToken cancellationToken)
{
Directory.CreateDirectory(dir);
var filePath = Path.Combine(dir, "test_file");
for (int i = 0; i < files; i++)
{
File.Delete($"{filePath}{i}TMP");
using var writer = File.CreateText($"{filePath}{i}");
for (int j = 0; j < 1024; j++)
{
writer.WriteLine(j);
}
}
await Task.Yield();
while (!cancellationToken.IsCancellationRequested)
{
for (int i = 0; i < files; i++)
{
File.Move($"{filePath}{i}", $"{filePath}{i}TMP");
}
for (int i = 0; i < files; i++)
{
File.Move($"{filePath}{i}TMP", $"{filePath}{i}");
}
await Task.Delay(100);
}
}
}
static Task WatchFile(string root, int watchers, CancellationToken cancellationToken)
{
if (!root.EndsWith(Path.DirectorySeparatorChar))
{
root += Path.DirectorySeparatorChar;
}
return Spawn(watchers, (i, ct) => Run(root, i+1, ct), cancellationToken);
static async Task Run(string root, int id, CancellationToken cancellationToken)
{
using var watcher = new PhysicalFilesWatcher(
root,
new FileSystemWatcher(root),
pollForChanges: false,
ExclusionFilters.Sensitive
);
var tcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
int num = 1;
using var registration = ChangeToken.OnChange(
() => watcher.CreateFileChangeToken($"appsettings.{id}.json"),
() =>
{
Console.Write($"{id}:{num++} ");
}
);
using var reg = cancellationToken.Register(() => tcs.TrySetResult(null));
await tcs.Task;
}
}
static async Task Spawn(int count, Func<int, CancellationToken, Task> factory, CancellationToken cancellationToken)
{
using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, default);
var tasks = new List<Task>();
for (int i = 0; i < count; i++)
{
tasks.Add(factory(i, cts.Token));
}
await Task.WhenAny(tasks);
if (!cancellationToken.IsCancellationRequested)
{
cts.Cancel();
}
await Task.WhenAll(tasks);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment