c# Debounce and Throttle
Tags: csharp, redis, distributedsystems, webdev
Published: 2024-06-02 18:35:32

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](https://www.nuget.org/packages/DistributedDebounceThrottle) and [DebounceThrottle](https://www.nuget.org/packages/DebounceThrottle).

Links:
- [DistributedDebounceThrottle Repo](https://github.com/coddicat/DistributedDebounceThrottle)
- [DebounceThrottle Repo]
(https://github.com/coddicat/DebounceThrottle)

## [DistributedDebounceThrottle](https://www.nuget.org/packages/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:

```shell
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:

1. **Configure Services:**
In your application's startup configuration, register **DistributedDebounceThrottle**:

```csharp
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);
}
```

2. **Inject and Use IDebounceThrottle:**
Inject **IDebounceThrottle** to access debounce and throttle dispatchers:

```csharp
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](https://www.nuget.org/packages/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:

```csharp
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):

```csharp
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:
- [DistributedDebounceThrottle Repo](https://github.com/coddicat/DistributedDebounceThrottle)
- [DebounceThrottle Repo]
(https://github.com/coddicat/DebounceThrottle)