Added github integration
This commit is contained in:
129
buffteks/lib/python3.11/site-packages/token_bucket/limiter.py
Normal file
129
buffteks/lib/python3.11/site-packages/token_bucket/limiter.py
Normal file
@@ -0,0 +1,129 @@
|
||||
# Copyright 2016 by Rackspace Hosting, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .storage_base import StorageBase
|
||||
|
||||
|
||||
class Limiter(object):
|
||||
"""Limits demand for a finite resource via keyed token buckets.
|
||||
|
||||
A limiter manages a set of token buckets that have an identical
|
||||
rate, capacity, and storage backend. Each bucket is referenced
|
||||
by a key, allowing for the independent tracking and limiting
|
||||
of multiple consumers of a resource.
|
||||
|
||||
Args:
|
||||
rate (float): Number of tokens per second to add to the
|
||||
bucket. Over time, the number of tokens that can be
|
||||
consumed is limited by this rate. Each token represents
|
||||
some percentage of a finite resource that may be
|
||||
utilized by a consumer.
|
||||
capacity (int): Maximum number of tokens that the bucket
|
||||
can hold. Once the bucket is full, additional tokens
|
||||
are discarded.
|
||||
|
||||
The bucket capacity has a direct impact on burst duration.
|
||||
Let M be the maximum possible token request rate, r the
|
||||
token generation rate (tokens/sec), and b the bucket
|
||||
capacity.
|
||||
|
||||
If r < M the maximum burst duration, in seconds, is:
|
||||
|
||||
T = b / (M - r)
|
||||
|
||||
Otherwise, if r >= M, it is not possible to exceed the
|
||||
replenishment rate, and therefore a consumer can burst
|
||||
at full speed indefinitely.
|
||||
|
||||
The maximum number of tokens that any one burst may
|
||||
consume is:
|
||||
|
||||
T * M
|
||||
|
||||
See also: https://en.wikipedia.org/wiki/Token_bucket#Burst_size
|
||||
storage (token_bucket.StorageBase): A storage engine to use for
|
||||
persisting the token bucket data. The following engines are
|
||||
available out of the box:
|
||||
|
||||
token_bucket.MemoryStorage
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
'_rate',
|
||||
'_capacity',
|
||||
'_storage',
|
||||
)
|
||||
|
||||
def __init__(self, rate, capacity, storage):
|
||||
if not isinstance(rate, (float, int)):
|
||||
raise TypeError('rate must be an int or float')
|
||||
|
||||
if rate <= 0:
|
||||
raise ValueError('rate must be > 0')
|
||||
|
||||
if not isinstance(capacity, int):
|
||||
raise TypeError('capacity must be an int')
|
||||
|
||||
if capacity < 1:
|
||||
raise ValueError('capacity must be >= 1')
|
||||
|
||||
if not isinstance(storage, StorageBase):
|
||||
raise TypeError('storage must be a subclass of StorageBase')
|
||||
|
||||
self._rate = rate
|
||||
self._capacity = capacity
|
||||
self._storage = storage
|
||||
|
||||
def consume(self, key, num_tokens=1):
|
||||
"""Attempt to take one or more tokens from a bucket.
|
||||
|
||||
If the specified token bucket does not yet exist, it will be
|
||||
created and initialized to full capacity before proceeding.
|
||||
|
||||
Args:
|
||||
key (bytes): A string or bytes object that specifies the
|
||||
token bucket to consume from. If a global limit is
|
||||
desired for all consumers, the same key may be used
|
||||
for every call to consume(). Otherwise, a key based on
|
||||
consumer identity may be used to segregate limits.
|
||||
Keyword Args:
|
||||
num_tokens (int): The number of tokens to attempt to
|
||||
consume, defaulting to 1 if not specified. It may
|
||||
be appropriate to ask for more than one token according
|
||||
to the proportion of the resource that a given request
|
||||
will use, relative to other requests for the same
|
||||
resource.
|
||||
|
||||
Returns:
|
||||
bool: True if the requested number of tokens were removed
|
||||
from the bucket (conforming), otherwise False (non-
|
||||
conforming). The entire number of tokens requested must
|
||||
be available in the bucket to be conforming. Otherwise,
|
||||
no tokens will be removed (it's all or nothing).
|
||||
"""
|
||||
|
||||
if not key:
|
||||
if key is None:
|
||||
raise TypeError('key may not be None')
|
||||
|
||||
raise ValueError('key must not be a non-empty string or bytestring')
|
||||
|
||||
if num_tokens is None:
|
||||
raise TypeError('num_tokens may not be None')
|
||||
|
||||
if num_tokens < 1:
|
||||
raise ValueError('num_tokens must be >= 1')
|
||||
|
||||
self._storage.replenish(key, self._rate, self._capacity)
|
||||
return self._storage.consume(key, num_tokens)
|
||||
Reference in New Issue
Block a user