Created
February 18, 2022 11:08
-
-
Save shivanshuraj1333/1e895a35d9a24e631e60f0a4249348d8 to your computer and use it in GitHub Desktop.
Basic rate limiter in Go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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