Skip to content

Instantly share code, notes, and snippets.

@tuscen
Forked from MihaZupan/RequestScheduler.cs
Created May 10, 2018 14:02
Show Gist options
  • Save tuscen/291970e0c65006190ff1a442b4a9dcc3 to your computer and use it in GitHub Desktop.
Save tuscen/291970e0c65006190ff1a442b4a9dcc3 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
namespace MihaZupan
{
/// <summary>
/// A simple request scheduler to help you conform to rate limiting
/// </summary>
public class RequestScheduler
{
private Queue<ManualResetEvent> RequestQueue = new Queue<ManualResetEvent>();
private object QueueLock = new object();
private int MaxBurst;
private int SafeInterval;
private Timer Timer;
private Stopwatch Stopwatch;
private long TimerIntervals = 0;
private int RequestCount = 0;
/// <summary>
/// Create a new <see cref="RequestScheduler"/>
/// </summary>
/// <param name="safeInterval">Cooldown interval in milliseconds</param>
/// <param name="maxBurst">Maximum number of requests to let through in quick succession</param>
public RequestScheduler(int safeInterval = 35, int maxBurst = 25)
{
SafeInterval = safeInterval;
MaxBurst = maxBurst;
Stopwatch = Stopwatch.StartNew();
Timer = new Timer(TimerCallback, null, SafeInterval, Timeout.Infinite);
}
private void TimerCallback(object state)
{
lock (QueueLock)
{
if (RequestQueue.Count > 0)
{
RequestQueue.Dequeue().Set();
}
else if (RequestCount > 0) RequestCount--;
}
TimerIntervals++;
long msElapsed = Stopwatch.ElapsedMilliseconds;
int wait = Math.Max(SafeInterval / 2, (int)((TimerIntervals + 1) * SafeInterval - msElapsed));
Timer.Change(wait, Timeout.Infinite);
}
/// <summary>
/// Will block the caller thread if MaxBurst of requests has been reached
/// </summary>
public void WaitOne()
{
ManualResetEvent mre = null;
lock (QueueLock)
{
if (RequestCount < MaxBurst)
{
RequestCount++;
return;
}
else
{
mre = new ManualResetEvent(false);
RequestQueue.Enqueue(mre);
}
}
mre.WaitOne();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment