https://github.com/da440dil/go-counter
Distributed rate limiting on Go
https://github.com/da440dil/go-counter
distributed go golang rate rate-limit rate-limiter rate-limiting redis
Last synced: 2 months ago
JSON representation
Distributed rate limiting on Go
- Host: GitHub
- URL: https://github.com/da440dil/go-counter
- Owner: da440dil
- License: mit
- Created: 2019-03-08T10:12:33.000Z (about 7 years ago)
- Default Branch: master
- Last Pushed: 2022-04-16T12:52:40.000Z (about 4 years ago)
- Last Synced: 2025-05-18T14:38:06.834Z (about 1 year ago)
- Topics: distributed, go, golang, rate, rate-limit, rate-limiter, rate-limiting, redis
- Language: Go
- Homepage:
- Size: 82 KB
- Stars: 5
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# go-counter
[](https://travis-ci.com/da440dil/go-counter)
[](https://coveralls.io/github/da440dil/go-counter?branch=master)
[](https://pkg.go.dev/github.com/da440dil/go-counter)
[](https://goreportcard.com/report/github.com/da440dil/go-counter)
Distributed rate limiting using [Redis](https://redis.io/).
[Example](./examples/limiter/main.go) usage:
```go
import (
"context"
"fmt"
"sync"
"time"
"github.com/da440dil/go-counter"
"github.com/go-redis/redis/v8"
)
func main() {
client := redis.NewClient(&redis.Options{})
defer client.Close()
ctx := context.Background()
key := "key"
err := client.Del(ctx, key).Err()
requireNoError(err)
// Create limiter with 2 limits.
limiter := counter.NewLimiter(
client,
// First limit: no more than 3 limiter calls within 1 second.
counter.WithLimit(time.Second, 3),
// Second limit: no more than 5 limiter calls within 2 seconds.
counter.WithLimit(time.Second*2, 5),
)
limit := func() {
r, err := limiter.Limit(ctx, key)
requireNoError(err)
fmt.Printf(
"Result: { ok: %v, counter: %v, remainder: %v, ttl: %v }\n",
r.OK(), r.Counter(), r.Remainder(), r.TTL(),
)
}
limitN := func(n int) {
var wg sync.WaitGroup
wg.Add(n)
for i := 0; i < n; i++ {
go func() {
defer wg.Done()
limit()
}()
}
wg.Wait()
}
limitN(4)
time.Sleep(time.Second) // wait for the next window to start
limitN(2)
// Output:
// Result: { ok: true, counter: 1, remainder: 2, ttl: 1s }
// Result: { ok: true, counter: 3, remainder: 0, ttl: 998ms }
// Result: { ok: true, counter: 2, remainder: 1, ttl: 998ms }
// Result: { ok: false, counter: 3, remainder: 0, ttl: 998ms }
// Result: { ok: true, counter: 5, remainder: 0, ttl: 993ms }
// Result: { ok: false, counter: 5, remainder: 0, ttl: 993ms }
}
func requireNoError(err error) {
if err != nil {
panic(err)
}
}
```