Background
I was calling a private API from C#, which had an API limit of 2 calls per second for each user. So there was a chance of getting "Rate Limit Reached Exception" if the API was being called more then twice in a second. That's why before making an API call, we had to make sure that the time interval between two call start is at least 500
milliseconds.
We were not just making API calls. After each call, we had to process a few other things. To make things manageable, we used a simple interval helper, which provided us the expected waiting time. Later that waiting time had been passed to Thread.Sleep()
, that's it. Let's check the time interval helper class and its usages.
Interval Helper Class
Here is the interface:
public interface IIntervalHelper<TInterval>
{
TInterval Interval();
DateTime StartDateTime();
void SetInterval(TInterval interval);
void Begin(DateTime? startDateTime = null);
TInterval PassedTime(DateTime? endDateTime = null);
TInterval RemainingTime(DateTime? endDateTime = null);
}
Using the interface to create the main helper class:
public class TimeSpanIntervalHelper : IIntervalHelper<TimeSpan>
{
private TimeSpan _interval;
private DateTime _startDateTime;
public TimeSpanIntervalHelper(TimeSpan interval)
{
SetInterval(interval);
}
public TimeSpan Interval()
{
return _interval;
}
public DateTime StartDateTime()
{
return _startDateTime;
}
public void SetInterval(TimeSpan interval)
{
_interval = interval;
}
public void Begin(DateTime? startDateTime = null)
{
_startDateTime = startDateTime ?? DateTime.Now;
}
public TimeSpan PassedTime(DateTime? endDateTime = null)
{
DateTime dateTime = endDateTime ?? DateTime.Now;
if (dateTime < _startDateTime)
{
throw new ArgumentException("EndDateTime should n't be less then StartDateTime");
}
TimeSpan difference = dateTime - _startDateTime;
return difference;
}
public TimeSpan RemainingTime(DateTime? endDateTime = null)
{
DateTime dateTime = endDateTime ?? DateTime.Now;
TimeSpan passedTime = PassedTime(dateTime);
TimeSpan remainingTime = _interval - passedTime;
return remainingTime;
}
}
Using the Helper Class
Here, we are setting the interval to 500
milliseconds.
TimeSpan interval = new TimeSpan(0, 0, 0, 0, 500);
var intervalHelper = new TimeSpanIntervalHelper(interval);
for (int i = 0; i < 10; i++)
{
intervalHelper.Begin();
DateTime endDateTime = DateTime.Now;
TimeSpan value = intervalHelper.PassedTime(endDateTime);
value = intervalHelper.RemainingTime(endDateTime);
Thread.Sleep(value);
}
For more, do check the TimeSpan_Use()
test method.
Other Options
RateGate
As Sacha Barber suggested, Rate Limiting is a great one to be used. It is packed with a lot of options. It is also available on NuGet.
Nuget: https://www.nuget.org/packages/JackLeitch.RateGate/
using (var rateGate = new RateGate(2, TimeSpan.FromSeconds(1)))
{
for (var i = 0; i < 10; i++)
{
rateGate.WaitToProceed();
}
}
Although I wasn't been able to do proper unit testing.
Do Check!!!
Inside the source code, we will find another helper class IntervalHelper
which manages things only in milliseconds. The usages are the same as the TimeSpanIntervalHelper
. Find usages code inside MilliSecond_Use()
test method.
History
- 31st July, 2019: Initial version