|
| 1 | +package sourcify |
| 2 | + |
| 3 | +import "time" |
| 4 | + |
| 5 | +// RateLimiter represents a rate limiter that controls the rate of actions using the token bucket algorithm. |
| 6 | +// It provides a mechanism to prevent an HTTP client from exceeding a certain rate of requests. |
| 7 | +// The Max field represents the maximum number of actions that can be performed per 'Duration'. |
| 8 | +// The Duration field represents the time duration for which 'Max' number of actions can be performed. |
| 9 | +// These fields together determine the capacity of the token bucket and the rate at which tokens are added to the bucket. |
| 10 | +// The bucket field is a channel that models the token bucket. A token is consumed from the bucket each time an action is taken. |
| 11 | +// The capacity of the bucket determines the maximum burstiness of the actions, while the rate at which tokens are added |
| 12 | +// to the bucket determines the sustainable average rate of actions. |
| 13 | +type RateLimiter struct { |
| 14 | + // Max is the maximum number of actions that can be performed per 'Duration'. |
| 15 | + Max int |
| 16 | + // Duration is the time duration for which 'Max' number of actions can be performed. |
| 17 | + Duration time.Duration |
| 18 | + // bucket is a channel that models the token bucket. A token is consumed from the bucket each time an action is taken. |
| 19 | + bucket chan struct{} |
| 20 | +} |
| 21 | + |
| 22 | +// NewRateLimiter creates a new rate limiter. |
| 23 | +// The rate limiter uses the token bucket algorithm to control the rate of actions. |
| 24 | +// It initially creates a bucket of capacity 'Max' and then adds a token to the bucket every 'Duration'. |
| 25 | +// It allows a maximum of 'Max' actions to be performed per 'Duration'. |
| 26 | +// If an action is attempted when the bucket is empty, the action blocks until a token is added to the bucket. |
| 27 | +// This blocking behaviour ensures that the rate of actions does not exceed the specified rate. |
| 28 | +// |
| 29 | +// Parameters: |
| 30 | +// max - The maximum number of actions that can be performed per 'duration'. It is the capacity of the token bucket. |
| 31 | +// duration - The time duration for which 'max' number of actions can be performed. |
| 32 | +// |
| 33 | +// Returns: |
| 34 | +// A pointer to the created RateLimiter. |
| 35 | +func NewRateLimiter(max int, duration time.Duration) *RateLimiter { |
| 36 | + bucket := make(chan struct{}, max) |
| 37 | + |
| 38 | + // Initially, the bucket is filled to its capacity. |
| 39 | + for i := 0; i < max; i++ { |
| 40 | + bucket <- struct{}{} |
| 41 | + } |
| 42 | + |
| 43 | + // A ticker is set up to add a token to the bucket every 'duration'. |
| 44 | + // If the bucket is full, the addition of a new token blocks until there is room in the bucket. |
| 45 | + // This ensures that the rate of actions doesn't exceed the specified rate. |
| 46 | + go func() { |
| 47 | + ticker := time.NewTicker(duration) |
| 48 | + for range ticker.C { |
| 49 | + bucket <- struct{}{} |
| 50 | + } |
| 51 | + }() |
| 52 | + |
| 53 | + return &RateLimiter{ |
| 54 | + Max: max, |
| 55 | + Duration: duration, |
| 56 | + bucket: bucket, |
| 57 | + } |
| 58 | +} |
| 59 | + |
| 60 | +// Wait is used to perform an action with rate limiting. |
| 61 | +// If the token bucket (i.e., 'bucket' field of RateLimiter) is empty, Wait blocks until a token is added to the bucket. |
| 62 | +// If a token is available in the bucket, Wait consumes the token and returns immediately, allowing the action to be performed. |
| 63 | +func (r *RateLimiter) Wait() { |
| 64 | + <-r.bucket |
| 65 | +} |
0 commit comments