Using SemaphoreSlim to Limit API Calls Per Minute
using System; using System.Net.Http; using System.Threading; using System.Threading.Tasks; class Program { private static readonly SemaphoreSlim Semaphore = new SemaphoreSlim(1); // Allows one task at a time to update the counter private static readonly int MaxCallsPerMinute = 100; private static readonly TimeSpan RateLimitInterval = TimeSpan.FromMinutes(1); private static int CallsMade = 0; private static DateTime RateLimitReset = DateTime.UtcNow.Add(RateLimitInterval); static async Task Main(string[] args) { string apiUrl = "https://api.example.com/endpoint"; // Simulate multiple API calls var tasks = new Task[200]; // Simulate 200 API requests for (int i = 0; i < tasks.Length; i++) { int requestId = i + 1; tasks[i] = MakeRateLimitedCall(apiUrl, requestId); } // Wait for all tasks to complete await Task.WhenAll(tasks); Console.WriteLine("All API calls completed."); } private static async Task MakeRateLimitedCall(string apiUrl, int requestId) { // Enforce rate-limiting logic await Semaphore.WaitAsync(); try { await ApplyRateLimit(requestId); // Simulate API call using (HttpClient client = new HttpClient()) { Console.WriteLine($"Request {requestId}: Started."); HttpResponseMessage response = await client.GetAsync(apiUrl); Console.WriteLine($"Request {requestId}: Completed with status {response.StatusCode}."); } } catch (Exception ex) { Console.WriteLine($"Request {requestId}: Error - {ex.Message}"); } finally { Semaphore.Release(); } } private static Task ApplyRateLimit(int requestId) { lock (Semaphore) { if (DateTime.UtcNow >= RateLimitReset) { // Reset the counters when the time window is up CallsMade = 0; RateLimitReset = DateTime.UtcNow.Add(RateLimitInterval); Console.WriteLine($"Request {requestId}: Rate limit reset."); } if (CallsMade >= MaxCallsPerMinute) { var waitTime = (int)(RateLimitReset - DateTime.UtcNow).TotalMilliseconds; Console.WriteLine($"Request {requestId}: Rate limit reached, waiting {waitTime / 1000} seconds..."); Monitor.Wait(Semaphore, waitTime); } CallsMade++; } return Task.CompletedTask; } }