### NewLeakyBucketEtcd Example Source: https://github.com/mennanov/limiters/blob/master/_autodocs/03-leaky-bucket.md Example of creating an Etcd backend for the Leaky Bucket rate limiter. ```go cli, _ := clientv3.New(clientv3.Config{Endpoints: []string{"localhost:2379"}}) backend := limiters.NewLeakyBucketEtcd(cli, "/ratelimiter/queue", 24*time.Hour, true) ``` -------------------------------- ### Instantiate Registry and ConcurrentBufferInMemory Source: https://github.com/mennanov/limiters/blob/master/_autodocs/01-core-interfaces.md Example demonstrating the creation of a Registry and its use in initializing a ConcurrentBufferInMemory. ```go registry := limiters.NewRegistry() buffer := limiters.NewConcurrentBufferInMemory(registry, 5*time.Minute, clock) ``` -------------------------------- ### NewLeakyBucketCosmosDB Example Source: https://github.com/mennanov/limiters/blob/master/_autodocs/03-leaky-bucket.md Example of creating a CosmosDB backend for the Leaky Bucket rate limiter. ```go client, _ := azcosmos.NewContainerClient(endpoint, dbName, containerName, credential) backend := limiters.NewLeakyBucketCosmosDB(client, "api-queue", time.Hour, true) ``` -------------------------------- ### NewLeakyBucketMemcached Example Source: https://github.com/mennanov/limiters/blob/master/_autodocs/03-leaky-bucket.md Example of creating a Memcached backend for the Leaky Bucket rate limiter. ```go cli, _ := memcache.New("localhost:11211") backend := limiters.NewLeakyBucketMemcached(cli, "limiter:queue", time.Hour, true) ``` -------------------------------- ### Instantiate SystemClock and FixedWindow Limiter Source: https://github.com/mennanov/limiters/blob/master/_autodocs/01-core-interfaces.md Example showing the creation of a SystemClock and its use in initializing a FixedWindow limiter. ```go clock := limiters.NewSystemClock() limiter := limiters.NewFixedWindow(100, time.Minute, backend, clock) ``` -------------------------------- ### NewLeakyBucketRedis Example Source: https://github.com/mennanov/limiters/blob/master/_autodocs/03-leaky-bucket.md Example of creating a Redis backend for the Leaky Bucket rate limiter. ```go cli := redis.NewClient(&redis.Options{Addr: "localhost:6379"}) backend := limiters.NewLeakyBucketRedis(cli, "limiter/queue", time.Hour, false) ``` -------------------------------- ### SlidingWindowMemcached Example Usage Source: https://github.com/mennanov/limiters/blob/master/_autodocs/05-sliding-window.md Example of creating a Memcached-based sliding window limiter. ```go cli, _ := memcache.New("localhost:11211") backend := limiters.NewSlidingWindowMemcached(cli, "limiter/api") ``` -------------------------------- ### NewLeakyBucketDynamoDB Example Source: https://github.com/mennanov/limiters/blob/master/_autodocs/03-leaky-bucket.md Example of creating a DynamoDB backend for the Leaky Bucket rate limiter. ```go client := dynamodb.NewFromConfig(cfg) props, _ := limiters.LoadDynamoDBTableProperties(ctx, client, "RateLimiters") backend := limiters.NewLeakyBucketDynamoDB(client, "api-queue", props, time.Hour, true) ``` -------------------------------- ### Token Bucket Configuration Example Source: https://github.com/mennanov/limiters/blob/master/_autodocs/QUICK-REFERENCE.md Demonstrates how to configure a Token Bucket for 100 requests per second with a burst capacity. Shows how to use the Limit method and handle ErrLimitExhausted. ```go limiter := limiters.NewTokenBucket( 1000, // burst capacity 10*time.Millisecond, // refill rate (100 req/sec) lock, backend, limiters.NewSystemClock(), limiters.NewStdLogger(), ) wait, err := limiter.Limit(ctx) if err == limiters.ErrLimitExhausted { // Wait 'wait' duration before retrying } ``` -------------------------------- ### Instantiate StdLogger and TokenBucket Limiter Source: https://github.com/mennanov/limiters/blob/master/_autodocs/01-core-interfaces.md Example demonstrating how to create a StdLogger and use it when initializing a TokenBucket limiter. ```go logger := limiters.NewStdLogger() limiter := limiters.NewTokenBucket(10, time.Second, lock, backend, clock, logger) ``` -------------------------------- ### Configuration Example with Redis Source: https://github.com/mennanov/limiters/blob/master/_autodocs/04-fixed-window.md Demonstrates how to configure and use the Fixed Window rate limiter with a Redis backend. Sets a rate of 100 requests per minute. ```go package main import ( "context" "log" "time" "github.com/redis/go-redis/v9" "github.com/mennanov/limiters" ) func main() { // 100 requests per minute redisClient := redis.NewClient(&redis.Options{Addr: "localhost:6379"}) backend := limiters.NewFixedWindowRedis(redisClient, "limiter/api") limiter := limiters.NewFixedWindow( 100, // 100 requests time.Minute, // per minute backend, limiters.NewSystemClock(), ) // Use in request handler wait, err := limiter.Limit(context.Background()) if err == limiters.ErrLimitExhausted { log.Printf("Rate limited, reset in %v\n", wait) } } ``` -------------------------------- ### Sliding Window Configuration Example Source: https://github.com/mennanov/limiters/blob/master/_autodocs/05-sliding-window.md Demonstrates how to configure and use a sliding window limiter with Redis backend, system clock, and specific rate limits. ```go package main import ( "context" "log" "time" "github.com/redis/go-redis/v9" "github.com/mennanov/limiters" ) func main() { // 100 requests per minute with 0.1 epsilon tolerance redisClient := redis.NewClient(&redis.Options{Addr: "localhost:6379"}) backend := limiters.NewSlidingWindowRedis(redisClient, "limiter/api") limiter := limiters.NewSlidingWindow( 100, // 100 requests time.Minute, // per minute backend, limiters.NewSystemClock(), 0.1, // epsilon for floating-point tolerance ) // Use in request handler wait, err := limiter.Limit(context.Background()) if err == limiters.ErrLimitExhausted { log.Printf("Rate limited, wait %v\n", wait) } } ``` -------------------------------- ### Token Bucket DynamoDB Backend Usage Example Source: https://github.com/mennanov/limiters/blob/master/_autodocs/08-dynamodb-cosmos.md Example Go code demonstrating how to set up and use the Token Bucket rate limiter with a DynamoDB backend. Includes loading table properties and creating the limiter. ```go package main import ( "context" "log" "time" "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/dynamodb" "github.com/mennanov/limiters" ) func main() { cfg, _ := config.LoadDefaultConfig(context.Background()) client := dynamodb.NewFromConfig(cfg) // Load table properties props, err := limiters.LoadDynamoDBTableProperties( context.Background(), client, "RateLimiters", ) if err != nil { log.Fatal(err) } // Create token bucket backend backend := limiters.NewTokenBucketDynamoDB( client, "api-global", // partition key value props, time.Hour, // TTL false, // raceCheck disabled ) // Create limiter limiter := limiters.NewTokenBucket( 100, 10*time.Millisecond, limiters.NewLockNoop(), backend, limiters.NewSystemClock(), limiters.NewStdLogger(), ) // Use wait, err := limiter.Limit(context.Background()) if err == limiters.ErrLimitExhausted { log.Printf("Rate limited, wait %v\n", wait) } } ``` -------------------------------- ### Full Leaky Bucket Configuration Example Source: https://github.com/mennanov/limiters/blob/master/_autodocs/03-leaky-bucket.md Demonstrates setting up a complete Leaky Bucket rate limiter using Redis for both backend storage and locking. Includes request queuing and error handling. ```go package main import ( "context" "log" "time" "github.com/redis/go-redis/v9" "github.com/mennanov/limiters" ) func main() { // Queue up to 1000 requests, process at 100 req/sec (10ms each) redisClient := redis.NewClient(&redis.Options{Addr: "localhost:6379"}) backend := limiters.NewLeakyBucketRedis(redisClient, "api/queue", 0, false) lock := limiters.NewLockRedis(redisClient, "api/queue-lock") limiter := limiters.NewLeakyBucket( 1000, // capacity (queue length) 10*time.Millisecond, // rate (100 req/sec) lock, backend, limiters.NewSystemClock(), limiters.NewStdLogger(), ) // Use in request handler wait, err := limiter.Limit(context.Background()) if err == limiters.ErrLimitExhausted { log.Printf("Queue full, would have waited %v\n", wait) } else { log.Printf("Request queued, will be processed in %v\n", wait) } } ``` -------------------------------- ### Context Timeout Examples Source: https://github.com/mennanov/limiters/blob/master/_autodocs/QUICK-REFERENCE.md Demonstrates setting context timeouts for different backend types to prevent hangs. Adjust duration based on expected latency. ```go // Fast: Local in-memory ctx, cancel := context.WithTimeout(ctx, 10*time.Millisecond) // Standard: Redis ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) // Slow: Etcd, DynamoDB ctx, cancel := context.WithTimeout(ctx, 1*time.Second) // Very slow: Cosmos DB with network delay ctx, cancel := context.WithTimeout(ctx, 5*time.Second) ``` -------------------------------- ### Example Usage of ConcurrentBufferRedis with ConcurrentBuffer Source: https://github.com/mennanov/limiters/blob/master/_autodocs/06-concurrent-buffer.md Demonstrates initializing a Redis-based backend and then using it with a general ConcurrentBuffer limiter. Requires a Redis client and a clock. ```go cli := redis.NewClient(&redis.Options{Addr: "localhost:6379"}) backend := limiters.NewConcurrentBufferRedis( cli, "api/active-requests", 5*time.Minute, clock, ) limiter := limiters.NewConcurrentBuffer( limiters.NewLockRedis(cli, "api/buffer-lock"), backend, 100, logger, ) ``` -------------------------------- ### Example Usage of ConcurrentBufferMemcached Source: https://github.com/mennanov/limiters/blob/master/_autodocs/06-concurrent-buffer.md Initializes a Memcached-based concurrent buffer backend. Requires a Memcached client and a clock. ```go cli, _ := memcache.New("localhost:11211") backend := limiters.NewConcurrentBufferMemcached(cli, "api:buffer", 5*time.Minute, clock) ``` -------------------------------- ### SlidingWindowRedis Example Usage Source: https://github.com/mennanov/limiters/blob/master/_autodocs/05-sliding-window.md Example of creating a Redis-based sliding window limiter and integrating it with a higher-level limiter. ```go cli := redis.NewClient(&redis.Options{Addr: "localhost:6379"}) backend := limiters.NewSlidingWindowRedis(cli, "limiter/api") limiter := limiters.NewSlidingWindow(100, time.Minute, backend, clock, 0.1) ``` -------------------------------- ### Run Local Tests with Make Source: https://github.com/mennanov/limiters/blob/master/README.md Execute local tests using the make command. Ensure the make utility is installed. ```bash make test ``` -------------------------------- ### Example LockPostgreSQL Usage Source: https://github.com/mennanov/limiters/blob/master/_autodocs/07-locks.md Shows how to create a LockPostgreSQL instance with a database connection and a specific advisory lock ID. ```go db, _ := sql.Open("postgres", "postgres://user:pass@localhost/dbname") lock := limiters.NewLockPostgreSQL(db, 1001) // ID 1001 for API limiter ``` -------------------------------- ### Context Timeout Example Source: https://github.com/mennanov/limiters/blob/master/_autodocs/10-errors-configuration.md Demonstrates how to set a timeout for a limiter operation using context.WithTimeout. If the operation exceeds the timeout, context.DeadlineExceeded is returned. ```go // Example 1: Request timeout ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) def cancel() wait, err := limiter.Limit(ctx) if err == context.DeadlineExceeded { log.Println("Rate limiter operation timed out") } ``` -------------------------------- ### Global Concurrency Limiting Source: https://github.com/mennanov/limiters/blob/master/_autodocs/06-concurrent-buffer.md Example of applying a global concurrency limit. Uses the fixed string 'global' as the key for the limiter. ```go err := limiter.Limit(ctx, "global") ``` -------------------------------- ### LoadDynamoDBTableProperties Example Usage Source: https://github.com/mennanov/limiters/blob/master/_autodocs/08-dynamodb-cosmos.md Example of how to load DynamoDB table properties using the AWS SDK. This is useful for initializing rate limiter backends. ```go client := dynamodb.NewFromConfig(cfg) props, err := limiters.LoadDynamoDBTableProperties(ctx, client, "RateLimiters") if err != nil { log.Fatal(err) } // Reuse props for multiple limiters ``` -------------------------------- ### Example LockMemcached Usage Source: https://github.com/mennanov/limiters/blob/master/_autodocs/07-locks.md Demonstrates creating a LockMemcached instance and configuring a custom exponential backoff strategy for lock acquisition. The default backoff uses constant intervals and a fixed number of retries. ```go cli, _ := memcache.New("localhost:11211") lock := limiters.NewLockMemcached(cli, "ratelimiter/api") // Custom backoff: 50ms exponential, max 5 seconds backoff := backoff.WithMaxRetries( backoff.NewExponentialBackOff(), 50, ) lock.WithLockAcquireBackoff(backoff) ``` -------------------------------- ### Context Cancellation Example Source: https://github.com/mennanov/limiters/blob/master/_autodocs/10-errors-configuration.md Illustrates how to cancel a limiter operation using context.WithCancel. If the context is canceled before the operation completes, context.Canceled is returned. ```go // Example 2: Cancellation signal ctx, cancel := context.WithCancel(context.Background()) go func() { time.Sleep(100 * time.Millisecond) cancel() }() wait, err := limiter.Limit(ctx) if err == context.Canceled { log.Println("Rate limiter operation canceled") } ``` -------------------------------- ### Per-IP Concurrency Limiting Source: https://github.com/mennanov/limiters/blob/master/_autodocs/06-concurrent-buffer.md Example of limiting concurrency based on the client's IP address. Constructs a key using an 'ip:' prefix and the remote address. ```go key := fmt.Sprintf("ip:%s", r.RemoteAddr) err := limiter.Limit(ctx, key) ``` -------------------------------- ### Token Bucket with Redis Lock and Backend Source: https://github.com/mennanov/limiters/blob/master/_autodocs/07-locks.md Configures a Token Bucket limiter using Redis for both the lock and the backend storage. This pattern is suitable for most distributed systems due to Redis's low latency and simple setup. ```go redisClient := redis.NewClient(&redis.Options{Addr: "localhost:6379"}) backend := limiters.NewTokenBucketRedis(redisClient, "limiter/api", 0, false) lock := limiters.NewLockRedis(redisClient, "limiter/api/lock") limiter := limiters.NewTokenBucket( 50, 100*time.Millisecond, lock, backend, limiters.NewSystemClock(), limiters.NewStdLogger(), ) ``` -------------------------------- ### Single Instance Token Bucket Limiter (In-Memory) Source: https://github.com/mennanov/limiters/blob/master/_autodocs/README.md Initializes an in-memory Token Bucket limiter for single-instance applications. This setup is suitable for basic rate limiting needs where distributed coordination is not required. ```go tokenBackend := limiters.NewTokenBucketInMemory() lock := limiters.NewLockNoop() limiter := limiters.NewTokenBucket( 10, // capacity time.Second, // refill rate (10 req/sec) lock, tokenBackend, limiters.NewSystemClock(), limiters.NewStdLogger(), ) wait, err := limiter.Limit(context.Background()) if err == limiters.ErrLimitExhausted { // Rate limited, wait 'wait' duration } ``` -------------------------------- ### In-Memory Backend for Single Instance Source: https://github.com/mennanov/limiters/blob/master/_autodocs/10-errors-configuration.md Demonstrates setting up an in-memory backend for token bucket limiters, suitable for development or single-server deployments. ```go tokenBackend := limiters.NewTokenBucketInMemory() lock := limiters.NewLockNoop() limiter := limiters.NewTokenBucket(100, 10*time.Millisecond, lock, tokenBackend, clock, logger) ``` -------------------------------- ### Clock Source: https://github.com/mennanov/limiters/blob/master/_autodocs/09-types.md Time source interface, mockable for testing. It provides a method to get the current time. ```APIDOC ## Clock ### Description Time source interface, mockable for testing. It provides a method to get the current time. ### Method - `Now() time.Time`: Returns the current time. ``` -------------------------------- ### Fixed Window Backend Implementations Source: https://github.com/mennanov/limiters/blob/master/_autodocs/QUICK-REFERENCE.md Shows how to instantiate fixed window counters using in-memory, Redis, Memcached, DynamoDB, and CosmosDB backends. ```go // Fixed Window NewFixedWindowInMemory() NewFixedWindowRedis(cli, prefix) NewFixedWindowMemcached(cli, prefix) NewFixedWindowDynamoDB(...) NewFixedWindowCosmosDB(...) ``` -------------------------------- ### Initialize FixedWindowMemcached Source: https://github.com/mennanov/limiters/blob/master/_autodocs/04-fixed-window.md Initializes a new FixedWindowMemcached storage backend. Requires a memcache client and a key prefix. ```go cli, _ := memcache.New("localhost:11211") backend := limiters.NewFixedWindowMemcached(cli, "limiter/api") ``` -------------------------------- ### Run All Local Tests and Benchmarks with Make Source: https://github.com/mennanov/limiters/blob/master/README.md Execute both local tests and benchmarks by simply running 'make'. This is a convenient shortcut for comprehensive local validation. ```bash make ``` -------------------------------- ### Initialize TokenBucketEtcd Backend Source: https://github.com/mennanov/limiters/blob/master/_autodocs/02-token-bucket.md Creates an Etcd-based token bucket backend for strongly consistent distributed coordination. Configurable with a key prefix, lease TTL, and race condition detection. ```go cli, _ := clientv3.New(clientv3.Config{Endpoints: []string{"localhost:2379"}}) backend := limiters.NewTokenBucketEtcd(cli, "/ratelimiter/api", 24*time.Hour, true) ``` -------------------------------- ### Initialize TokenBucketMemcached Backend Source: https://github.com/mennanov/limiters/blob/master/_autodocs/02-token-bucket.md Creates a Memcached-based token bucket backend. Supports configurable key, TTL, and CAS checks for race conditions. Be aware of potential data eviction due to memory pressure. ```go cli, _ := memcache.New("localhost:11211") backend := limiters.NewTokenBucketMemcached(cli, "limiter:bucket", time.Hour, true) ``` -------------------------------- ### LeakyBucketStateBackend Source: https://github.com/mennanov/limiters/blob/master/_autodocs/09-types.md Backend interface for leaky bucket state storage. It defines methods for getting, setting, and resetting the state of a leaky bucket. ```APIDOC ## LeakyBucketStateBackend ### Description Backend interface for leaky bucket state storage. It defines methods for getting, setting, and resetting the state of a leaky bucket. ### Methods - `State(ctx context.Context) (LeakyBucketState, error)`: Retrieves the current state of the leaky bucket. - `SetState(ctx context.Context, state LeakyBucketState) error`: Sets the state of the leaky bucket. - `Reset(ctx context.Context) error`: Resets the leaky bucket state. ``` -------------------------------- ### Token Bucket with Cosmos DB Backend in Go Source: https://github.com/mennanov/limiters/blob/master/_autodocs/08-dynamodb-cosmos.md Demonstrates how to initialize and use a Token Bucket rate limiter with a Cosmos DB backend in Go. Requires Azure SDKs and the 'limiters' library. ```go package main import ( "context" "log" "time" "github.com/Azure/azure-sdk-for-go/sdk/azidentity" "github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos" "github.com/mennanov/limiters" ) func main() { credential, _ := azidentity.NewDefaultAzureCredential(nil) client, _ := azcosmos.NewContainerClient( "https://myaccount.documents.azure.com:443/", "mydb", "ratelimiters", credential, ) // Create token bucket backend backend := limiters.NewTokenBucketCosmosDB( client, "api-global", // partition key value time.Hour, // TTL in seconds false, // raceCheck disabled ) // Create limiter limiter := limiters.NewTokenBucket( 100, 10*time.Millisecond, limiters.NewLockNoop(), backend, limiters.NewSystemClock(), limiters.NewStdLogger(), ) // Use wait, err := limiter.Limit(context.Background()) if err == limiters.ErrLimitExhausted { log.Printf("Rate limited, wait %v\n", wait) } } ``` -------------------------------- ### API Rate Limiting by User Source: https://github.com/mennanov/limiters/blob/master/_autodocs/06-concurrent-buffer.md Example of limiting concurrency for a specific user. Constructs a key using a 'user:' prefix and the provided userID. ```go key := fmt.Sprintf("user:%s", userID) err := limiter.Limit(ctx, key) ``` -------------------------------- ### Initialize TokenBucketRedis Backend Source: https://github.com/mennanov/limiters/blob/master/_autodocs/02-token-bucket.md Creates a Redis-based token bucket backend for distributed deployments. Supports cluster clients and configurable key expiration and race condition checking. ```go cli := redis.NewClient(&redis.Options{Addr: "localhost:6379"}) backend := limiters.NewTokenBucketRedis(cli, "limiter/api", time.Hour, false) ``` -------------------------------- ### Concurrent Buffer Backend Implementations Source: https://github.com/mennanov/limiters/blob/master/_autodocs/QUICK-REFERENCE.md Demonstrates how to create concurrent buffer limiters using in-memory, Redis, and Memcached backends. ```go // Concurrent Buffer NewConcurrentBufferInMemory(registry, ttl, clock) NewConcurrentBufferRedis(cli, key, ttl, clock) NewConcurrentBufferMemcached(cli, key, ttl, clock) ``` -------------------------------- ### Per-Endpoint Concurrency Limiting Source: https://github.com/mennanov/limiters/blob/master/_autodocs/06-concurrent-buffer.md Example of limiting concurrency for a specific API endpoint. Constructs a key using an 'endpoint:' prefix and the request's URL path. ```go key := fmt.Sprintf("endpoint:%s", r.URL.Path) err := limiter.Limit(ctx, key) ``` -------------------------------- ### Configure and Use Token Bucket Limiter with Redis Source: https://github.com/mennanov/limiters/blob/master/_autodocs/02-token-bucket.md Demonstrates how to configure and use a Token Bucket rate limiter with Redis as the backend. Sets up a Redis client, a Token Bucket backend, and a lock, then initializes the limiter with specific capacity and refill rate. ```go package main import ( "context" "log" "time" "github.com/redis/go-redis/v9" "github.com/mennanov/limiters" ) func main() { // 10 requests per second, with burst capacity of 50 redisClient := redis.NewClient(&redis.Options{Addr: "localhost:6379"}) backend := limiters.NewTokenBucketRedis(redisClient, "api/limits", 0, false) lock := limiters.NewLockRedis(redisClient, "api/limit-lock") limiter := limiters.NewTokenBucket( 50, // capacity (burst) 100*time.Millisecond, // refill rate (10 req/sec) lock, backend, limiters.NewSystemClock(), limiters.NewStdLogger(), ) // Use in request handler wait, err := limiter.Limit(context.Background()) if err == limiters.ErrLimitExhausted { log.Printf("Rate limited, wait %v\n", wait) } } ``` -------------------------------- ### SlidingWindow Constructor and Methods Source: https://github.com/mennanov/limiters/blob/master/_autodocs/QUICK-REFERENCE.md Shows the SlidingWindow constructor and its Limit method. Requires capacity, rate, a backend, a clock, and an epsilon value. ```go NewSlidingWindow(capacity int64, rate time.Duration, backend SlidingWindowIncrementer, clock Clock, epsilon float64) *SlidingWindow func (s *SlidingWindow) Limit(ctx context.Context) (time.Duration, error) ``` -------------------------------- ### Run Local Benchmarks with Make Source: https://github.com/mennanov/limiters/blob/master/README.md Execute local benchmarks using the make command. This is useful for performance analysis. ```bash make benchmark ``` -------------------------------- ### Etcd Backend for Strong Consistency Source: https://github.com/mennanov/limiters/blob/master/_autodocs/10-errors-configuration.md Illustrates configuring an Etcd backend for token bucket limiters, providing strong consistency for critical systems. ```go cli, _ := clientv3.New(clientv3.Config{ Endpoints: []string{"localhost:2379"}, }) tokenBackend := limiters.NewTokenBucketEtcd(cli, "/ratelimiter/api", 24*time.Hour, true) lock := limiters.NewLockEtcd(cli, "/ratelimiter/api/lock", logger) limiter := limiters.NewTokenBucket(100, 10*time.Millisecond, lock, tokenBackend, clock, logger) ``` -------------------------------- ### Initialize TokenBucketInMemory Backend Source: https://github.com/mennanov/limiters/blob/master/_autodocs/02-token-bucket.md Creates an in-memory token bucket backend. Suitable for single-instance deployments where state loss on restart is acceptable. ```go backend := limiters.NewTokenBucketInMemory() limiter := limiters.NewTokenBucket(10, time.Second, limiters.NewLockNoop(), backend, clock, logger) ``` -------------------------------- ### Distributed Token Bucket Limiter with DynamoDB for AWS Lambda Source: https://github.com/mennanov/limiters/blob/master/_autodocs/README.md Implements a distributed Token Bucket limiter for AWS Lambda using DynamoDB. This example demonstrates loading table properties and configuring the backend for serverless environments. ```go client := dynamodb.NewFromConfig(cfg) props, _ := limiters.LoadDynamoDBTableProperties(ctx, client, "RateLimiters") backend := limiters.NewTokenBucketDynamoDB( client, "api-global", props, time.Hour, false, ) limiter := limiters.NewTokenBucket( 100, 10*time.Millisecond, limiters.NewLockNoop(), backend, limiters.NewSystemClock(), limiters.NewStdLogger(), ) ``` -------------------------------- ### gRPC Global Token Bucket Rate Limiter Source: https://github.com/mennanov/limiters/blob/master/README.md Example of setting up a global token bucket rate limiter for a gRPC service using etcd for locking and Redis for the backend. It includes a unary interceptor to apply rate limiting to all requests. ```go // examples/example_grpc_simple_limiter_test.go raterate := time.Second * 3 limiter := limiters.NewTokenBucket( 2, rate, limiters.NewLockerEtcd(etcdClient, "/ratelimiter_lock/simple/", limiters.NewStdLogger()), limiters.NewTokenBucketRedis( redisClient, "ratelimiter/simple", rate, false), limiters.NewSystemClock(), limiters.NewStdLogger(), ) // Add a unary interceptor middleware to rate limit all requests. s := grpc.NewServer(grpc.UnaryInterceptor( func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { w, err := limiter.Limit(ctx) if err == limiters.ErrLimitExhausted { return nil, status.Errorf(codes.ResourceExhausted, "try again later in %s", w) } else if err != nil { // The limiter failed. This error should be logged and examined. log.Println(err) return nil, status.Error(codes.Internal, "internal error") } return handler(ctx, req) })) ``` -------------------------------- ### NewLeakyBucketCosmosDB Constructor Source: https://github.com/mennanov/limiters/blob/master/_autodocs/03-leaky-bucket.md Initializes an Azure Cosmos DB-based state storage. Requires a container with partition key '/partitionKey' and enabled default TTL. ```go type CosmosDBLeakyBucketItem struct { ID string PartitionKey string State LeakyBucketState Version int64 TTL int64 } type LeakyBucketCosmosDB struct{} func NewLeakyBucketCosmosDB( client *azcosmos.ContainerClient, partitionKey string, ttl time.Duration, raceCheck bool, ) *LeakyBucketCosmosDB ``` -------------------------------- ### Token Bucket Backend Implementations Source: https://github.com/mennanov/limiters/blob/master/_autodocs/QUICK-REFERENCE.md Provides constructors for various token bucket state backends, including in-memory and distributed systems like Redis, Etcd, Memcached, DynamoDB, and CosmosDB. ```go // Token Bucket NewTokenBucketInMemory() NewTokenBucketRedis(cli, prefix, ttl, raceCheck) NewTokenBucketEtcd(cli, prefix, ttl, raceCheck) NewTokenBucketMemcached(cli, key, ttl, raceCheck) NewTokenBucketDynamoDB(client, partitionKey, props, ttl, raceCheck) NewTokenBucketCosmosDB(client, partitionKey, ttl, raceCheck) ``` -------------------------------- ### FixedWindow Constructor and Methods Source: https://github.com/mennanov/limiters/blob/master/_autodocs/QUICK-REFERENCE.md Defines the FixedWindow constructor and its Limit method. Requires capacity, rate, a backend, and a clock. ```go NewFixedWindow(capacity int64, rate time.Duration, backend FixedWindowIncrementer, clock Clock) *FixedWindow func (f *FixedWindow) Limit(ctx context.Context) (time.Duration, error) ``` -------------------------------- ### New SlidingWindowRedis Constructor Source: https://github.com/mennanov/limiters/blob/master/_autodocs/05-sliding-window.md Initializes a Redis-based counter storage for distributed rate limiting. Requires a Redis client and a key prefix for namespacing. ```go func NewSlidingWindowRedis(cli redis.UniversalClient, prefix string) *SlidingWindowRedis ``` -------------------------------- ### NewFixedWindowRedis Constructor Source: https://github.com/mennanov/limiters/blob/master/_autodocs/04-fixed-window.md Initializes a Redis-based backend for the Fixed Window rate limiter, designed for distributed environments. It uses pipelined commands for atomic operations and requires a Redis client and a key prefix. ```go func NewFixedWindowRedis(cli redis.UniversalClient, prefix string) *FixedWindowRedis ``` ```go cli := redis.NewClient(&redis.Options{Addr: "localhost:6379"}) backend := limiters.NewFixedWindowRedis(cli, "limiter/api") limiter := limiters.NewFixedWindow(100, time.Minute, backend, clock) ``` -------------------------------- ### Fixed Window Limiter Initialization Source: https://github.com/mennanov/limiters/blob/master/_autodocs/QUICK-REFERENCE.md Initializes a Fixed Window limiter for simple request limits. Specify the number of requests and the time window. Backend and clock are required. ```go limiter := limiters.NewFixedWindow( 100, // 100 requests time.Minute, // per minute backend, clock, ) ``` -------------------------------- ### New SlidingWindowMemcached Constructor Source: https://github.com/mennanov/limiters/blob/master/_autodocs/05-sliding-window.md Initializes a Memcached-based counter storage for two windows. Requires a Memcached client and a key prefix. ```go func NewSlidingWindowMemcached(cli *memcache.Client, prefix string) *SlidingWindowMemcached ``` -------------------------------- ### Package Import Path Source: https://github.com/mennanov/limiters/blob/master/_autodocs/QUICK-REFERENCE.md Shows the correct import path for the limiters package and how to use exported symbols. ```go import "github.com/mennanov/limiters" // All exported symbols are in package limiters limiter := limiters.NewTokenBucket(...) err := limiters.ErrLimitExhausted ``` -------------------------------- ### TokenBucket Constructor and Methods Source: https://github.com/mennanov/limiters/blob/master/_autodocs/QUICK-REFERENCE.md Defines the constructor for TokenBucket and its core methods for limiting and taking tokens. Requires context, capacity, refill rate, a locker, backend, clock, and logger. ```go NewTokenBucket(capacity int64, refillRate time.Duration, locker DistLocker, backend TokenBucketStateBackend, clock Clock, logger Logger) *TokenBucket func (t *TokenBucket) Limit(ctx context.Context) (time.Duration, error) func (t *TokenBucket) Take(ctx context.Context, tokens int64) (time.Duration, error) func (t *TokenBucket) TakeMax(ctx context.Context, tokens int64) (int64, error) func (t *TokenBucket) Reset(ctx context.Context) error ``` -------------------------------- ### NewLeakyBucketDynamoDB Constructor Source: https://github.com/mennanov/limiters/blob/master/_autodocs/03-leaky-bucket.md Initializes an AWS DynamoDB-based state storage. Requires a table with a String Partition Key and enabled TTL. ```go type LeakyBucketDynamoDB struct{} func NewLeakyBucketDynamoDB( client *dynamodb.Client, partitionKey string, tableProps DynamoDBTableProperties, ttl time.Duration, raceCheck bool, ) *LeakyBucketDynamoDB ``` -------------------------------- ### SlidingWindow Constructor Source: https://github.com/mennanov/limiters/blob/master/_autodocs/05-sliding-window.md Initializes a new SlidingWindow rate limiter. Requires capacity, rate, a backend incrementer, a clock source, and an epsilon for capacity comparison. ```go type SlidingWindow struct { // Unexported fields } func NewSlidingWindow( capacity int64, rate time.Duration, slidingWindowIncrementer SlidingWindowIncrementer, clock Clock, epsilon float64, ) *SlidingWindow ``` -------------------------------- ### Sliding Window Limiter Initialization Source: https://github.com/mennanov/limiters/blob/master/_autodocs/QUICK-REFERENCE.md Initializes a Sliding Window limiter for smooth distribution of requests. Configure request count, time window, backend, clock, and an epsilon tolerance. ```go limiter := limiters.NewSlidingWindow( 100, // 100 requests time.Minute, // per minute backend, clock, 0.1, // 10% epsilon tolerance ) ``` -------------------------------- ### Redis Backend for Distributed Deployments Source: https://github.com/mennanov/limiters/blob/master/_autodocs/10-errors-configuration.md Shows how to configure a Redis backend for token bucket limiters, ideal for distributed systems. ```go cli := redis.NewClient(&redis.Options{ Addr: "localhost:6379", }) tokenBackend := limiters.NewTokenBucketRedis(cli, "limiter/api", 0, false) lock := limiters.NewLockRedis(cli, "limiter/api/lock") limiter := limiters.NewTokenBucket(100, 10*time.Millisecond, lock, tokenBackend, clock, logger) ``` -------------------------------- ### FixedWindow Constructor Source: https://github.com/mennanov/limiters/blob/master/_autodocs/04-fixed-window.md Initializes a new FixedWindow rate limiter. Requires specifying the request capacity per window, the window duration, a backend incrementer, and a clock source. ```go func NewFixedWindow( capacity int64, rate time.Duration, fixedWindowIncrementer FixedWindowIncrementer, clock Clock, ) *FixedWindow ``` -------------------------------- ### NewLeakyBucketRedis Constructor Source: https://github.com/mennanov/limiters/blob/master/_autodocs/03-leaky-bucket.md Initializes a Redis-based state storage for distributed deployments. Supports Redis cluster. ```go type LeakyBucketRedis struct{} func NewLeakyBucketRedis( cli redis.UniversalClient, prefix string, ttl time.Duration, raceCheck bool, ) *LeakyBucketRedis ``` -------------------------------- ### NewLeakyBucketMemcached Constructor Source: https://github.com/mennanov/limiters/blob/master/_autodocs/03-leaky-bucket.md Initializes a Memcached-based state storage. Data may be evicted under memory pressure. ```go type LeakyBucketMemcached struct{} func NewLeakyBucketMemcached( cli *memcache.Client, key string, ttl time.Duration, raceCheck bool, ) *LeakyBucketMemcached ``` -------------------------------- ### NewLeakyBucketEtcd Constructor Source: https://github.com/mennanov/limiters/blob/master/_autodocs/03-leaky-bucket.md Initializes an Etcd-based state storage for strongly-consistent coordination. Requires careful management of compaction and defragmentation. ```go type LeakyBucketEtcd struct{} func NewLeakyBucketEtcd( cli *clientv3.Client, prefix string, ttl time.Duration, raceCheck bool, ) *LeakyBucketEtcd ``` -------------------------------- ### Fixed Window for Simple Per-Minute Limits Source: https://github.com/mennanov/limiters/blob/master/_autodocs/10-errors-configuration.md Configure a fixed window limiter for simple per-minute request limits. ```go capacity := int64(1000) // 1000 requests rate := time.Minute // Per minute limiter := limiters.NewFixedWindow(capacity, rate, backend, clock) ``` -------------------------------- ### Token Bucket with PostgreSQL Lock Source: https://github.com/mennanov/limiters/blob/master/_autodocs/07-locks.md Illustrates setting up a Token Bucket limiter with a PostgreSQL lock. Note that a custom implementation is required for the PostgreSQL backend as it's not provided by the library. ```go db, _ := sql.Open("postgres", "postgres://user:pass@localhost/dbname") // Note: PostgreSQL backend implementation would need custom implementation lock := limiters.NewLockPostgreSQL(db, 1001) // Backend setup (custom implementation not provided by library) ``` -------------------------------- ### Take Method for Multiple Tokens Source: https://github.com/mennanov/limiters/blob/master/_autodocs/02-token-bucket.md Takes a specified number of tokens from the bucket, suitable for batch operations. Returns the required wait time if insufficient tokens are available. ```go wait, err := limiter.Take(ctx, 5) if err == limiters.ErrLimitExhausted { fmt.Printf("Need to wait %v before retrying\n", wait) } ``` -------------------------------- ### Sliding Window Backend Implementations Source: https://github.com/mennanov/limiters/blob/master/_autodocs/QUICK-REFERENCE.md Lists constructors for sliding window counters, with support for in-memory, Redis, Memcached, DynamoDB, and CosmosDB. ```go // Sliding Window NewSlidingWindowInMemory() NewSlidingWindowRedis(cli, prefix) NewSlidingWindowMemcached(cli, prefix) NewSlidingWindowDynamoDB(...) NewSlidingWindowCosmosDB(...) ``` -------------------------------- ### NewSlidingWindow Source: https://github.com/mennanov/limiters/blob/master/_autodocs/05-sliding-window.md Initializes a new Sliding Window rate limiter. It requires parameters for capacity, rate, a backend incrementer, a clock source, and an epsilon for tolerance. ```APIDOC ## NewSlidingWindow ### Description Initializes a new Sliding Window rate limiter. It requires parameters for capacity, rate, a backend incrementer, a clock source, and an epsilon for tolerance. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Constructor Signature ```go func NewSlidingWindow( capacity int64, rate time.Duration, slidingWindowIncrementer SlidingWindowIncrementer, clock Clock, epsilon float64, ) *SlidingWindow ``` ### Parameters Table | Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | capacity | `int64` | Yes | — | Max requests per window period | | rate | `time.Duration` | Yes | — | Window size (e.g., 1s) | | slidingWindowIncrementer | `SlidingWindowIncrementer` | Yes | — | Backend counter implementation | | clock | `Clock` | Yes | — | Time source | | epsilon | `float64` | Yes | — | Tolerance threshold for capacity comparison (e.g., 0.1) | ### Returns - `*SlidingWindow`: Initialized `*SlidingWindow` ready for rate limiting. ### Algorithm Details Maintains counters for current and previous windows. The weighted total of both determines if the limit is exceeded. This smooths out burst traffic at window boundaries. ### Epsilon Usage Floating-point tolerance when comparing weighted total to capacity. Prevents rejection due to rounding errors. ``` -------------------------------- ### DynamoDB Backend for AWS Deployments Source: https://github.com/mennanov/limiters/blob/master/_autodocs/10-errors-configuration.md Demonstrates configuring a DynamoDB backend for token bucket limiters, suitable for AWS deployments and serverless functions. ```go cfg, _ := config.LoadDefaultConfig(context.Background()) client := dynamodb.NewFromConfig(cfg) props, _ := limiters.LoadDynamoDBTableProperties(ctx, client, "RateLimiters") tokenBackend := limiters.NewTokenBucketDynamoDB(client, "api-global", props, time.Hour, false) limiter := limiters.NewTokenBucket(100, 10*time.Millisecond, limiters.NewLockNoop(), tokenBackend, clock, logger) ``` -------------------------------- ### SlidingWindowInMemory Constructor Source: https://github.com/mennanov/limiters/blob/master/_autodocs/05-sliding-window.md Initializes an in-memory backend for the Sliding Window rate limiter. Suitable for single-instance deployments. ```go type SlidingWindowInMemory struct{} func NewSlidingWindowInMemory() *SlidingWindowInMemory func (s *SlidingWindowInMemory) Increment( ctx context.Context, prev, curr time.Time, _ time.Duration, ) (int64, int64, error) ``` ```go backend := limiters.NewSlidingWindowInMemory() limiter := limiters.NewSlidingWindow(100, time.Minute, backend, clock, 0.1) ``` -------------------------------- ### NewFixedWindow Source: https://github.com/mennanov/limiters/blob/master/_autodocs/04-fixed-window.md Initializes a new FixedWindow rate limiter. It requires a capacity, rate duration, a backend incrementer, and a clock source. ```APIDOC ## NewFixedWindow ### Description Initializes a new FixedWindow rate limiter. ### Parameters #### Path Parameters - **capacity** (int64) - Required - Max requests per window - **rate** (time.Duration) - Required - Window duration (e.g., 1s for per-second limits) - **fixedWindowIncrementer** (FixedWindowIncrementer) - Required - Backend counter implementation - **clock** (Clock) - Required - Time source ### Return Initialized `*FixedWindow` ready for rate limiting. ``` -------------------------------- ### Fixed Window for Per-Second Limits Source: https://github.com/mennanov/limiters/blob/master/_autodocs/10-errors-configuration.md Configure a fixed window limiter for per-second request limits. ```go capacity := int64(100) // 100 requests rate := time.Second // Per second limiter := limiters.NewFixedWindow(capacity, rate, backend, clock) ``` -------------------------------- ### Lock Acquisition with Timeout Source: https://github.com/mennanov/limiters/blob/master/_autodocs/07-locks.md Shows how to acquire a lock with a specific timeout using `context.WithTimeout`. This prevents indefinite blocking if the lock cannot be obtained within the specified duration. ```go // Example: Lock with timeout ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := lock.Lock(ctx); err == context.DeadlineExceeded { log.Println("Could not acquire lock within 5 seconds") } ``` -------------------------------- ### LeakyBucket Constructor and Methods Source: https://github.com/mennanov/limiters/blob/master/_autodocs/QUICK-REFERENCE.md Shows the constructor for LeakyBucket and its methods for limiting requests and resetting the bucket. Requires context, capacity, rate, a locker, backend, clock, and logger. ```go NewLeakyBucket(capacity int64, rate time.Duration, locker LeakyBucketStateBackend, clock Clock, logger Logger) *LeakyBucket func (l *LeakyBucket) Limit(ctx context.Context) (time.Duration, error) func (l *LeakyBucket) Reset(ctx context.Context) error ``` -------------------------------- ### Lock Implementations Source: https://github.com/mennanov/limiters/blob/master/_autodocs/QUICK-REFERENCE.md Shows various implementations for distributed lockers, including Noop, Etcd, Consul, Zookeeper, Redis, Memcached, and PostgreSQL. ```go NewLockNoop() NewLockEtcd(cli, prefix, logger) NewLockConsul(lock) NewLockZookeeper(lock) NewLockRedis(pool, mutexName, options...) NewLockMemcached(client, mutexName) NewLockPostgreSQL(db, id) ``` -------------------------------- ### SystemClock Implementation Source: https://github.com/mennanov/limiters/blob/master/_autodocs/01-core-interfaces.md A concrete implementation of the `Clock` interface that uses Go's standard `time` package to provide real system time and sleep functionality. ```APIDOC ## SystemClock Implementation ### Description Real system clock using Go's `time` package. ### Methods #### NewSystemClock - **Returns**: `*SystemClock` - **Description**: Creates a new instance of SystemClock. #### Now - **Parameters**: — - **Returns**: `time.Time` - **Description**: Returns current system time. #### Sleep - **Parameters**: `d time.Duration` - **Returns**: — - **Description**: Pauses execution for the specified duration. ``` -------------------------------- ### Leaky Bucket Limiter Initialization Source: https://github.com/mennanov/limiters/blob/master/_autodocs/QUICK-REFERENCE.md Initializes a Leaky Bucket limiter for smooth processing. Requires queue capacity, process rate, a lock, backend, clock, and logger. ```go limiter := limiters.NewLeakyBucket( 1000, // queue capacity 10*time.Millisecond, // process rate lock, backend, clock, logger, ) wait, err := limiter.Limit(ctx) if err == limiters.ErrLimitExhausted { // Queue is full } ``` -------------------------------- ### Leaky Bucket Backend Implementations Source: https://github.com/mennanov/limiters/blob/master/_autodocs/QUICK-REFERENCE.md Lists constructors for different leaky bucket state backends, supporting in-memory and distributed storage solutions. ```go // Leaky Bucket NewLeakyBucketInMemory() NewLeakyBucketRedis(cli, prefix, ttl, raceCheck) NewLeakyBucketEtcd(cli, prefix, ttl, raceCheck) NewLeakyBucketMemcached(cli, key, ttl, raceCheck) NewLeakyBucketDynamoDB(client, partitionKey, props, ttl, raceCheck) NewLeakyBucketCosmosDB(client, partitionKey, ttl, raceCheck) ``` -------------------------------- ### Initialize ConcurrentBufferMemcached Source: https://github.com/mennanov/limiters/blob/master/_autodocs/06-concurrent-buffer.md Initializes a Memcached-based concurrent buffer. Requires a Memcached client, a key, a TTL, and a clock source. Note that Memcached may evict data under memory pressure. ```go type ConcurrentBufferMemcached struct{} func NewConcurrentBufferMemcached( cli *memcache.Client, key string, ttl time.Duration, clock Clock, ) *ConcurrentBufferMemcached ``` -------------------------------- ### Initialize TokenBucketCosmosDB Source: https://github.com/mennanov/limiters/blob/master/_autodocs/02-token-bucket.md Initializes a Token Bucket limiter using Azure Cosmos DB for state storage. Requires an Azure SDK Cosmos container client. The raceCheck parameter enables version-based conflict detection. ```go type CosmosDBTokenBucketItem struct { ID string PartitionKey string State TokenBucketState Version int64 TTL int64 } type TokenBucketCosmosDB struct{} func NewTokenBucketCosmosDB( client *azcosmos.ContainerClient, partitionKey string, ttl time.Duration, raceCheck bool, ) *TokenBucketCosmosDB ``` ```go client, _ := azcosmos.NewContainerClient(endpoint, dbName, containerName, credential) backend := limiters.NewTokenBucketCosmosDB(client, "api-global", time.Hour, true) ``` -------------------------------- ### SystemClock Implementation Source: https://github.com/mennanov/limiters/blob/master/_autodocs/01-core-interfaces.md A concrete implementation of the Clock interface that uses Go's standard 'time' package for real system time. It also includes a Sleep method. ```go type SystemClock struct{} func NewSystemClock() *SystemClock func (c *SystemClock) Now() time.Time func (c *SystemClock) Sleep(d time.Duration) ``` -------------------------------- ### Initialize ConcurrentBufferRedis Source: https://github.com/mennanov/limiters/blob/master/_autodocs/06-concurrent-buffer.md Initializes a Redis-based concurrent buffer. Requires a Redis client, a key for the sorted set, a TTL for members, and a clock source. Suitable for distributed systems. ```go type ConcurrentBufferRedis struct{} func NewConcurrentBufferRedis( cli redis.UniversalClient, key string, ttl time.Duration, clock Clock, ) *ConcurrentBufferRedis ``` -------------------------------- ### Cosmos DB Token Bucket Backend Source: https://github.com/mennanov/limiters/blob/master/_autodocs/10-errors-configuration.md Initializes a Token Bucket limiter using Cosmos DB as the backend for multi-region consistency. Suitable for Azure deployments. ```go credential, _ := azidentity.NewDefaultAzureCredential(nil) client, _ := azcosmos.NewContainerClient(endpoint, dbName, containerName, credential) tokenBackend := limiters.NewTokenBucketCosmosDB(client, "api-global", time.Hour, false) limiter := limiters.NewTokenBucket(100, 10*time.Millisecond, limiters.NewLockNoop(), tokenBackend, clock, logger) ```