Running a C# loop to update 500 users via /api/v2/users and hitting 429 Too Many Requests immediately. The docs say to respect the Retry-After header but my HttpClient is just crashing the thread. Here is the code: var response = await client.PutAsync($"/api/v2/users/{id}", content); what is the proper backoff logic here?
The 429 isn’t just about rate limits, it’s about your retry strategy being too aggressive. You’re probably blasting requests without honoring the Retry-After header or implementing exponential backoff. Genesys Cloud throttles hard on bulk updates.
Here’s a quick C# extension method to handle the backoff properly. It reads the Retry-After header and waits that many seconds before retrying. If the header is missing, it falls back to a default delay.
public static async Task<HttpResponseMessage> PutAsyncWithRetry(this HttpClient client, string url, HttpContent content, int maxRetries = 3)
{
for (int i = 0; i < maxRetries; i++)
{
var response = await client.PutAsync(url, content);
if (response.StatusCode == HttpStatusCode.TooManyRequests)
{
var retryAfter = response.Headers.RetryAfter?.Delta?.TotalSeconds ?? 2.0;
Console.WriteLine($"Rate limited. Waiting {retryAfter}s...");
await Task.Delay(TimeSpan.FromSeconds(retryAfter));
}
else
{
return response;
}
}
throw new HttpRequestException("Max retries exceeded");
}
Don’t forget to serialize your JSON payload correctly too. If the schema validation fails, you’ll get a 400, not a 429, so check your logs.
That backoff logic fixed the crash. Switched to HttpClient with Polly for retries and it’s holding up. Just remember to parse the Retry-After header as seconds, not milliseconds. The API is strict about that. Bulk updates are still slow but at least they don’t fail now.