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;
}
}