Rate Limiting in Visual Basic .NET

Here’s the translation of the rate limiting example from Go to Visual Basic .NET:

Rate limiting is an important mechanism for controlling resource utilization and maintaining quality of service. Visual Basic .NET supports rate limiting with threads, timers, and channels (implemented using concurrent collections).

Imports System
Imports System.Threading
Imports System.Collections.Concurrent

Module RateLimiting
    Sub Main()
        ' First we'll look at basic rate limiting. Suppose
        ' we want to limit our handling of incoming requests.
        ' We'll serve these requests off a queue of the same name.
        Dim requests As New ConcurrentQueue(Of Integer)
        For i As Integer = 1 To 5
            requests.Enqueue(i)
        Next

        ' This timer will trigger every 200 milliseconds.
        ' This is the regulator in our rate limiting scheme.
        Dim limiter As New Timer(AddressOf ProcessRequest, requests, 0, 200)

        ' We'll use this to signal when all requests are processed
        Dim done As New ManualResetEvent(False)

        ' By waiting for the timer to trigger before serving each request,
        ' we limit ourselves to 1 request every 200 milliseconds.
        Sub ProcessRequest(state As Object)
            Dim queue = DirectCast(state, ConcurrentQueue(Of Integer))
            Dim request As Integer
            If queue.TryDequeue(request) Then
                Console.WriteLine($"request {request} {DateTime.Now}")
            Else
                limiter.Dispose()
                done.Set()
            End If
        End Sub

        ' Wait for all requests to be processed
        done.WaitOne()

        ' We may want to allow short bursts of requests in
        ' our rate limiting scheme while preserving the
        ' overall rate limit. We can accomplish this by
        ' using a semaphore. This burstyLimiter will allow
        ' bursts of up to 3 events.
        Dim burstyLimiter As New SemaphoreSlim(3, 3)

        ' Every 200 milliseconds we'll try to add a new
        ' permit to burstyLimiter, up to its limit of 3.
        Dim burstyTimer As New Timer(
            Sub()
                burstyLimiter.Release(1)
            End Sub,
            Nothing,
            0,
            200)

        ' Now simulate 5 more incoming requests. The first
        ' 3 of these will benefit from the burst capability
        ' of burstyLimiter.
        Dim burstyRequests As New ConcurrentQueue(Of Integer)
        For i As Integer = 1 To 5
            burstyRequests.Enqueue(i)
        Next

        Dim burstyDone As New ManualResetEvent(False)

        Sub ProcessBurstyRequest(state As Object)
            Dim queue = DirectCast(state, ConcurrentQueue(Of Integer))
            Dim request As Integer
            If queue.TryDequeue(request) Then
                burstyLimiter.Wait()
                Console.WriteLine($"request {request} {DateTime.Now}")
                ThreadPool.QueueUserWorkItem(AddressOf ProcessBurstyRequest, queue)
            Else
                burstyTimer.Dispose()
                burstyDone.Set()
            End If
        End Sub

        ThreadPool.QueueUserWorkItem(AddressOf ProcessBurstyRequest, burstyRequests)

        ' Wait for all bursty requests to be processed
        burstyDone.WaitOne()
    End Sub
End Module

Running our program, we would see the first batch of requests handled once every ~200 milliseconds as desired.

For the second batch of requests, we would serve the first 3 immediately because of the burstable rate limiting, then serve the remaining 2 with ~200ms delays each.

In this Visual Basic .NET implementation:

  1. We use ConcurrentQueue(Of Integer) instead of channels to store requests.
  2. Timer is used to implement the rate limiting logic.
  3. SemaphoreSlim is used to implement the bursty limiter.
  4. ThreadPool.QueueUserWorkItem is used to process requests asynchronously.
  5. ManualResetEvent is used to signal when all requests have been processed.

This implementation preserves the core concepts of rate limiting and bursty rate limiting from the original example, adapted to the idioms and available constructs in Visual Basic .NET.