Skip to content

Instantly share code, notes, and snippets.

@shivanshuraj1333
Created February 18, 2022 11:08
Show Gist options
  • Save shivanshuraj1333/1e895a35d9a24e631e60f0a4249348d8 to your computer and use it in GitHub Desktop.
Save shivanshuraj1333/1e895a35d9a24e631e60f0a4249348d8 to your computer and use it in GitHub Desktop.
Basic rate limiter in Go
package main
import (
"context"
"fmt"
"log"
"sync"
"time"
)
func main() {
fmt.Println("Rate Limiter Started...")
done := make(chan struct{})
reqChan := make(chan struct{})
rt := &RateLimiter{3, 0, sync.Mutex{}}
go timer(rt, done)
// test case, 100, 200, 300, 800
time.Sleep(100 * time.Millisecond) // msSinceEpoch: 100
fmt.Printf("Rate limited: %t \n", rt.ShouldRateLimit(&Request{100}))
time.Sleep(100 * time.Millisecond) // msSinceEpoch: 200
fmt.Printf("Rate limited: %t \n", rt.ShouldRateLimit(&Request{200}))
time.Sleep(100 * time.Millisecond) // msSinceEpoch: 300
fmt.Printf("Rate limited: %t \n", rt.ShouldRateLimit(&Request{300}))
time.Sleep(500 * time.Millisecond) // msSinceEpoch: 800
fmt.Printf("Rate limited: %t \n", rt.ShouldRateLimit(&Request{800}))
time.Sleep(400 * time.Millisecond) // msSinceEpoch: 1200
sendConcurrentReq(rt)
// waiting for 5 seconds before starting continues req at an interval of 100ms
time.Sleep(time.Second * 5)
// msSinceEpoch: 1200 + 5000 = 6200
// sending req for next 5 sec
go sendReq(rt, reqChan)
<-reqChan
//<-done
}
type Request struct {
MsSinceEpoch uint64
}
type RateLimiter struct {
RequestsPerSecond uint64
cnt uint64
mu sync.Mutex
}
func (r *RateLimiter) ShouldRateLimit(req *Request) bool {
fmt.Printf("Req timestamp :%v ", req.MsSinceEpoch)
r.mu.Lock()
defer r.mu.Unlock()
if r.cnt < r.RequestsPerSecond {
r.cnt++
return false
} else {
r.cnt = 0
return true
}
}
func timer(rt *RateLimiter, done chan struct{}) {
defer close(done)
for {
select {
case <-time.NewTicker(time.Second).C:
log.Println("Resetting RateLimiter")
rt.cnt = 0
}
}
}
func sendReq(rt *RateLimiter, reqc chan struct{}) {
var counter uint64
ctx, cancel := context.WithCancel(context.Background())
go func(ctx context.Context) {
select {
case <-time.NewTicker(time.Millisecond * 5500).C:
cancel()
}
}(ctx)
for {
select {
case <-ctx.Done():
close(reqc)
return
default:
time.Sleep(100 * time.Millisecond)
counter += 100
fmt.Printf("Rate limited: %t \n", rt.ShouldRateLimit(&Request{6200 + counter}))
}
}
}
func sendConcurrentReq(rt *RateLimiter) {
wgp := new(sync.WaitGroup)
wgp.Add(5)
go func(r *RateLimiter, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf("Rate limited: %t \n", r.ShouldRateLimit(&Request{1200}))
}(rt, wgp)
go func(r *RateLimiter, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf("Rate limited: %t \n", r.ShouldRateLimit(&Request{1200}))
}(rt, wgp)
go func(r *RateLimiter, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf("Rate limited: %t \n", r.ShouldRateLimit(&Request{1200}))
}(rt, wgp)
go func(r *RateLimiter, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf("Rate limited: %t \n", r.ShouldRateLimit(&Request{1200}))
}(rt, wgp)
go func(r *RateLimiter, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf("Rate limited: %t \n", r.ShouldRateLimit(&Request{1200}))
}(rt, wgp)
wgp.Wait()
}
// output
/*
Rate Limiter Started...
Req timestamp :100 Rate limited: false
Req timestamp :200 Rate limited: false
Req timestamp :300 Rate limited: false
Req timestamp :800 Rate limited: true
2022/02/18 16:33:35 Resetting RateLimiter
Req timestamp :1200 Rate limited: false
Req timestamp :1200 Rate limited: false
Req timestamp :1200 Rate limited: false
Req timestamp :1200 Rate limited: true
Req timestamp :1200 Rate limited: false
2022/02/18 16:33:36 Resetting RateLimiter
2022/02/18 16:33:37 Resetting RateLimiter
2022/02/18 16:33:38 Resetting RateLimiter
2022/02/18 16:33:39 Resetting RateLimiter
2022/02/18 16:33:40 Resetting RateLimiter
Req timestamp :6300 Rate limited: false
Req timestamp :6400 Rate limited: false
Req timestamp :6500 Rate limited: false
Req timestamp :6600 Rate limited: true
Req timestamp :6700 Rate limited: false
Req timestamp :6800 Rate limited: false
Req timestamp :6900 Rate limited: false
2022/02/18 16:33:41 Resetting RateLimiter
Req timestamp :7000 Rate limited: false
Req timestamp :7100 Rate limited: false
Req timestamp :7200 Rate limited: false
Req timestamp :7300 Rate limited: true
Req timestamp :7400 Rate limited: false
Req timestamp :7500 Rate limited: false
Req timestamp :7600 Rate limited: false
Req timestamp :7700 Rate limited: true
Req timestamp :7800 Rate limited: false
Req timestamp :7900 Rate limited: false
2022/02/18 16:33:42 Resetting RateLimiter
Req timestamp :8000 Rate limited: false
Req timestamp :8100 Rate limited: false
Req timestamp :8200 Rate limited: false
Req timestamp :8300 Rate limited: true
Req timestamp :8400 Rate limited: false
Req timestamp :8500 Rate limited: false
Req timestamp :8600 Rate limited: false
Req timestamp :8700 Rate limited: true
Req timestamp :8800 Rate limited: false
Req timestamp :8900 Rate limited: false
2022/02/18 16:33:43 Resetting RateLimiter
Req timestamp :9000 Rate limited: false
Req timestamp :9100 Rate limited: false
Req timestamp :9200 Rate limited: false
Req timestamp :9300 Rate limited: true
Req timestamp :9400 Rate limited: false
Req timestamp :9500 Rate limited: false
Req timestamp :9600 Rate limited: false
Req timestamp :9700 Rate limited: true
Req timestamp :9800 Rate limited: false
Req timestamp :9900 Rate limited: false
2022/02/18 16:33:44 Resetting RateLimiter
Req timestamp :10000 Rate limited: false
Req timestamp :10100 Rate limited: false
Req timestamp :10200 Rate limited: false
Req timestamp :10300 Rate limited: true
Req timestamp :10400 Rate limited: false
Req timestamp :10500 Rate limited: false
Req timestamp :10600 Rate limited: false
Req timestamp :10700 Rate limited: true
Req timestamp :10800 Rate limited: false
Req timestamp :10900 Rate limited: false
2022/02/18 16:33:45 Resetting RateLimiter
Req timestamp :11000 Rate limited: false
Req timestamp :11100 Rate limited: false
Req timestamp :11200 Rate limited: false
Req timestamp :11300 Rate limited: true
Req timestamp :11400 Rate limited: false
Req timestamp :11500 Rate limited: false
Req timestamp :11600 Rate limited: false
Req timestamp :11700 Rate limited: true
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment