Skip to content

Instantly share code, notes, and snippets.

@kierenj
Last active February 1, 2018 17:22
Show Gist options
  • Save kierenj/a21a0d23cac162c8332f3d65266213eb to your computer and use it in GitHub Desktop.
Save kierenj/a21a0d23cac162c8332f3d65266213eb to your computer and use it in GitHub Desktop.
public class MyLimitedApiClient
{
private static readonly object _syncRoot = new object();
private DateTime? _nextRequestTimeSlot = null;
private readonly HttpClient _http;
private static readonly TimeSpan RateLimitedInterval = TimeSpan.FromSeconds(0.1); // 10 per sec
public async Task<T> GetJson<T>(string url) where T : class
{
var serialiser = new DataContractJsonSerializer(typeof(T));
retry: // just for the "goto" controversy!
DateTime slot;
lock (_syncRoot)
{
slot = _nextRequestTimeSlot ?? DateTime.UtcNow;
_nextRequestTimeSlot = slot + TimeSpan.FromSeconds(RateLimitedInterval);
}
var toWait = (slot - DateTime.UtcNow).TotalSeconds;
if (toWait > 0)
{
// wait with a super-efficient async delay
await Task.Delay((int)(toWait * 1000));
}
// do the request!
var response = await _http.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
// check for limited response
var limited = response.StatusCode == (System.Net.HttpStatusCode)429;
if (limited)
{
// get a new slot
goto retry;
}
// read the response.. as an example, we'll deserialise as an object
using (var stream = await response.Content.ReadAsStreamAsync())
{
var result = serialiser.ReadObject(stream) as T;
return result;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment