mirror of
https://github.com/azaion/annotations.git
synced 2026-04-22 22:26:31 +00:00
d42409de7d
fix configs fix build scripts
72 lines
2.4 KiB
C#
72 lines
2.4 KiB
C#
using System.Collections.Concurrent;
|
|
|
|
namespace Azaion.Common.Extensions;
|
|
|
|
public static class ThrottleExt
|
|
{
|
|
private class ThrottleState(Func<Task> action)
|
|
{
|
|
public Func<Task> Action { get; set; } = action ?? throw new ArgumentNullException(nameof(action));
|
|
public bool IsCoolingDown = false;
|
|
public bool CallScheduledDuringCooldown = false;
|
|
public Task CooldownTask = Task.CompletedTask;
|
|
public readonly object StateLock = new();
|
|
}
|
|
|
|
private static readonly ConcurrentDictionary<Guid, ThrottleState> ThrottlerStates = new();
|
|
|
|
public static void Throttle(Func<Task> action, Guid actionId, TimeSpan interval, bool scheduleCallAfterCooldown = false)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(action);
|
|
if (actionId == Guid.Empty)
|
|
throw new ArgumentException("Throttle identifier cannot be empty.", nameof(actionId));
|
|
if (interval <= TimeSpan.Zero)
|
|
throw new ArgumentOutOfRangeException(nameof(interval), "Interval must be positive.");
|
|
|
|
var state = ThrottlerStates.GetOrAdd(actionId, new ThrottleState(action));
|
|
state.Action = action;
|
|
|
|
lock (state.StateLock)
|
|
{
|
|
if (!state.IsCoolingDown)
|
|
{
|
|
state.IsCoolingDown = true;
|
|
state.CooldownTask = ExecuteAndManageCooldownStaticAsync(actionId, interval, state);
|
|
}
|
|
else
|
|
{
|
|
if (scheduleCallAfterCooldown)
|
|
state.CallScheduledDuringCooldown = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
private static async Task ExecuteAndManageCooldownStaticAsync(Guid throttleId, TimeSpan interval, ThrottleState state)
|
|
{
|
|
try
|
|
{
|
|
await state.Action();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"[Throttled Action Error - ID: {throttleId}] {ex.GetType().Name}: {ex.Message}");
|
|
}
|
|
finally
|
|
{
|
|
await Task.Delay(interval);
|
|
|
|
lock (state.StateLock)
|
|
{
|
|
if (state.CallScheduledDuringCooldown)
|
|
{
|
|
state.CallScheduledDuringCooldown = false;
|
|
state.CooldownTask = ExecuteAndManageCooldownStaticAsync(throttleId, interval, state);
|
|
}
|
|
else
|
|
{
|
|
state.IsCoolingDown = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |