In software development, managing the frequency of function executions is crucial to ensure efficiency, avoid redundant operations, and prevent system overloads. Whether you're working on a distributed system or a local application, implementing debounce and throttle mechanisms can significantly improve performance and reliability. In this article, we introduce two powerful .NET libraries designed for these purposes: DistributedDebounceThrottle and DebounceThrottle.
Links:
DistributedDebounceThrottle: A Distributed Solution
DistributedDebounceThrottle is a .NET library designed to facilitate debounce and throttle mechanisms in distributed system environments. Leveraging Redis for state management and distributed locking, this library ensures that function executions are properly debounced or throttled across multiple instances, preventing excessive or unintended operations.
Key Features
- Debounce: Ensures a function is executed only once after a specified interval since the last call, minimizing redundant operations.
- Throttle: Limits the execution frequency of a function, ensuring it's not executed more than once within a specified timeframe.
- Distributed Locks: Implements the RedLock algorithm for distributed locking to coordinate debounce and throttle logic across distributed systems.
- Redis Integration: Utilizes Redis for managing timestamps and locks, offering a scalable solution for state synchronization.
Getting Started
Installation
Install DistributedDebounceThrottle via NuGet:
dotnet add package DistributedDebounceThrottle
Usage
To integrate DistributedDebounceThrottle in your application, ensure you have a Redis instance ready for connection. Here's how to get started:
- Configure Services: In your application's startup configuration, register DistributedDebounceThrottle:
public void ConfigureServices(IServiceCollection services)
{
// Using an existing IConnectionMultiplexer instance:
services.AddDistributedDebounceThrottle(settings);
// Or, initiating a new IConnectionMultiplexer with a connection string:
services.AddDistributedDebounceThrottle(redisConnectionString, settings);
}
- Inject and Use IDebounceThrottle: Inject IDebounceThrottle to access debounce and throttle dispatchers:
public class SampleService
{
private readonly IDispatcher _throttler;
public SampleService(IDebounceThrottle debounceThrottle)
{
_throttler = debounceThrottle.ThrottleDispatcher("uniqueDispatcherId", TimeSpan.FromSeconds(5));
}
public Task ExecuteThrottledOperation()
{
return _throttler.DispatchAsync(async () =>
{
// Operation logic here.
});
}
}
Configuration
Customize your debounce and throttle settings via DebounceThrottleSettings:
- RedisKeysPrefix: A prefix for all Redis keys (default "debounce-throttle:").
- RedLockExpiryTime: The expiry time for the distributed locks (default TimeSpan.FromSeconds(10)).
DebounceThrottle: A Local Solution
For developers who don't need distributed functionalities and are looking for a local solution, DebounceThrottle provides simple yet effective debounce and throttle dispatchers. This library supports asynchronous actions and handles exceptions, ensuring that all Task results from dispatcher calls are consistent with the result of a single invocation.
Debounce Demo
The following example shows how to display entered text after stopping pressing keys for 1000 milliseconds:
class Program
{
static void Main(string[] args)
{
string str = "";
var debounceDispatcher = new DebounceDispatcher(1000);
while(true)
{
var key = Console.ReadKey(true);
//trigger when to stop and exit
if (key.Key == ConsoleKey.Escape) break;
str += key.KeyChar;
//every keypress iteration call dispatcher but the Action will be invoked only after stopping pressing and waiting 1000 milliseconds
debounceDispatcher.Debounce(() =>
{
Console.WriteLine($"{str} - {DateTime.UtcNow.ToString("hh:mm:ss.fff")}");
str = "";
});
}
}
}
Throttle Demo
The following example shows how to call an action every 100 milliseconds but invoke it only once in 1000 milliseconds (after the last invoking completed):
class Program
{
static void Main(string[] args)
{
bool stop = false;
//trigger when to stop and exit
Task.Run(() => { Console.ReadKey(true); stop = true; });
var throttleDispatcher = new ThrottleDispatcher(1000);
do
{
//every iteration call dispatcher but the Action will be invoked only once in 1500 milliseconds (500 action work time + 1000 interval)
throttleDispatcher.ThrottleAsync(async () =>
{
Console.WriteLine($"{ DateTime.UtcNow.ToString("hh:mm:ss.fff") }");
await Task.Delay(500);
});
//iteration every 100 milliseconds
Thread.Sleep(100);
}
while (!stop); //wait trigger to stop and exit
}
}
Conclusion
Whether you need a distributed solution with Redis integration or a simple local library, both DistributedDebounceThrottle and DebounceThrottle provide robust debounce and throttle mechanisms for .NET applications. By integrating these libraries, you can enhance your application's performance and reliability, effectively managing function executions to prevent system overloads and redundant operations.
Links:
Top comments (0)