namespace OpenQuery.Services; public sealed class RateLimiter : IAsyncDisposable { private readonly SemaphoreSlim _semaphore; public RateLimiter(int maxConcurrentRequests) { _semaphore = new SemaphoreSlim(maxConcurrentRequests, maxConcurrentRequests); } public async Task ExecuteAsync(Func> action, CancellationToken cancellationToken = default) { await _semaphore.WaitAsync(cancellationToken); try { return await action(); } finally { _semaphore.Release(); } } public async Task ExecuteAsync(Func action, CancellationToken cancellationToken = default) { await _semaphore.WaitAsync(cancellationToken); try { await action(); } finally { _semaphore.Release(); } } public async ValueTask DisposeAsync() { _semaphore.Dispose(); } }