Skip to content

Instantly share code, notes, and snippets.

@cocowalla
Last active July 7, 2022 13:49
Show Gist options
  • Save cocowalla/5d181b82b9a986c6761585000901d1b8 to your computer and use it in GitHub Desktop.
Save cocowalla/5d181b82b9a986c6761585000901d1b8 to your computer and use it in GitHub Desktop.
Simple debounce
using System;
using System.Threading;
using System.Threading.Tasks;
namespace MyNamespace
{
public class Debouncer : IDisposable
{
private readonly CancellationTokenSource cts = new CancellationTokenSource();
private readonly TimeSpan waitTime;
private int counter;
public Debouncer(TimeSpan? waitTime = null)
{
this.waitTime = waitTime ?? TimeSpan.FromSeconds(3);
}
public void Debouce(Action action)
{
var current = Interlocked.Increment(ref this.counter);
Task.Delay(this.waitTime).ContinueWith(task =>
{
// Is this the last task that was queued?
if (current == this.counter && !this.cts.IsCancellationRequested)
action();
task.Dispose();
}, this.cts.Token);
}
public void Dispose()
{
this.cts.Cancel();
}
}
}
using System;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Primitives;
namespace MyNamespace
{
public static class IConfigurationExtensions
{
/// <summary>
/// Perform an action when configuration changes. Note this requires config sources to be added with
/// `reloadOnChange` enabled
/// </summary>
/// <param name="config">Configuration to watch for changes</param>
/// <param name="action">Action to perform when <paramref name="config"/> is changed</param>
public static void OnChange(this IConfiguration config, Action action)
{
// IConfiguration's change detection is based on FileSystemWatcher, which will fire multiple change
// events for each change - Microsoft's code is buggy in that it doesn't bother to debounce/dedupe
// https://github.com/aspnet/AspNetCore/issues/2542
var debouncer = new Debouncer(TimeSpan.FromSeconds(3));
ChangeToken.OnChange<object>(config.GetReloadToken, _ => debouncer.Debouce(action), null);
}
}
}
...
var config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", false, true)
.SetBasePath(Directory.GetCurrentDirectory())
.Build();
config.OnChange(() =>
{
// TODO: Config has been changed, do stuff here
});
...
@lonix1
Copy link

lonix1 commented Jul 7, 2022

Hopefully an async overload will make it into v7 later this year. If this is still important to you please upvote to help prioritise it? :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment