I'm using Polly to make parallel API calls. The server however can't process more than 25 calls per second and so I'm wondering if there is a way to add a 1s delay after each batch of 25 calls?
var policy = Policy
.Handle<HttpRequestException>()
.RetryAsync(3);
foreach (var mediaItem in uploadedMedia)
{
var mediaRequest = new HttpRequestMessage { *** }
async Task<string> func()
{
var response = await client.SendAsync(mediaRequest);
return await response.Content.ReadAsStringAsync();
}
tasks.Add(policy.ExecuteAsync(() => func()));
}
await Task.WhenAll(tasks);
I added a count as per the suggestion below but doesn't seem to work
foreach (var mediaItem in uploadedMedia.Items)
{
var mediaRequest = new HttpRequestMessage
{
RequestUri = new Uri($"https://u48ydao1w4.execute-api.ap-southeast-2.amazonaws.com/test/downloads/thumbnails/{mediaItem.filename.S}"),
Method = HttpMethod.Get,
Headers = {
{ "id-token", id_Token },
{ "access-token", access_Token }
}
};
async Task<string> func()
{
if (count == 24)
{
Thread.Sleep(1000);
count = 0;
}
var response = await client.SendAsync(mediaRequest);
count++;
return await response.Content.ReadAsStringAsync();
}
tasks.Add(policy.ExecuteAsync(() => func()));
}
await Task.WhenAll(tasks);
foreach (var t in tasks)
{
var postResponse = await t;
urls.Add(postResponse);
}
The Polly library currently lacks a rate-limiting policy (requests/time). Fortunately this functionality is relatively easy to implement using a
SemaphoreSlim
. The trick to make the rate-limiting happen is to configure the capacity of the semaphore equal to the dividend (requests), and delay theRelease
of the semaphore for a time span equal to the divisor (time), after acquiring the semaphore. This way the rate limit will be applied consistently to any possible time window.Update: I realized that the Polly library is extensible, and allows to implement custom policies with custom functionality. So I'm scraping my original suggestion in favor of the custom
RateLimitAsyncPolicy
class below:This policy ensures that no more than
maxOperationsPerTimeUnit
operations will be started during any time window oftimeUnit
size. The duration of the operations is not taken into account. In other words no restriction is imposed on how many operations can be running concurrently at any given moment. This restriction can be optionally imposed by theBulkheadAsync
policy. Combining these two policies (theRateLimitAsyncPolicy
and theBulkheadAsync
) is possible, as shown in the example below:The order is important only for the
RetryAsync
policy, that must be placed first for a reason explained in the documentation:Similarly the
RateLimitPolicy
must follow theRetry
, so that each retry to be considered an independent operation, and to count towards the rate limit.