From 2c9f2a30f7af905eac384016137e5fb5cf2efd7e Mon Sep 17 00:00:00 2001 From: Zev Averbach Date: Fri, 11 Aug 2023 08:01:18 +0300 Subject: [PATCH] fixed first algo so it adds as many tokens as needed after more than one time period has passed --- my_limiter/algos.py | 15 ++++++++++----- my_limiter/config.py | 1 - my_limiter/wsgi.py | 17 +++++++++++++++++ 3 files changed, 27 insertions(+), 6 deletions(-) delete mode 100644 my_limiter/config.py diff --git a/my_limiter/algos.py b/my_limiter/algos.py index f7b0642..1afb7c6 100644 --- a/my_limiter/algos.py +++ b/my_limiter/algos.py @@ -9,7 +9,7 @@ class TooManyRequests(Exception): pass -def token_bucket(ip: str): +def token_bucket(ip: str) -> str: """ Tokens are put in the bucket at preset rates periodically. Once the bucket is full, no more tokens are added. @@ -17,17 +17,22 @@ def token_bucket(ip: str): """ REFILL_EVERY_SECONDS = TIME_INTERVAL_SECONDS NUM_TOKENS_TO_REFILL = 4 - MAX_CAPACITY = 4 + MAX_CAPACITY = 8 entry = TOKEN_BUCKET.get(ip) if entry is None: - TOKEN_BUCKET[ip] = {'tokens': 4, 'last_refilled': dt.datetime.now().timestamp()} + TOKEN_BUCKET[ip] = {'tokens': MAX_CAPACITY, 'last_refilled': dt.datetime.now().timestamp()} else: - if dt.datetime.now().timestamp() >= entry['last_refilled'] + REFILL_EVERY_SECONDS: + last_refilled = entry['last_refilled'] + now = dt.datetime.now().timestamp() + if now >= last_refilled + REFILL_EVERY_SECONDS: + num_tokens_to_refill = int((now - last_refilled) // REFILL_EVERY_SECONDS * NUM_TOKENS_TO_REFILL) entry['last_refilled'] = dt.datetime.now().timestamp() - entry['tokens'] = min(entry['tokens'] + NUM_TOKENS_TO_REFILL, MAX_CAPACITY) + entry['tokens'] = min(entry['tokens'] + num_tokens_to_refill, MAX_CAPACITY) + left = TOKEN_BUCKET[ip]['tokens'] if left == 0: raise TooManyRequests + TOKEN_BUCKET[ip]['tokens'] -= 1 \ No newline at end of file diff --git a/my_limiter/config.py b/my_limiter/config.py deleted file mode 100644 index 8b13789..0000000 --- a/my_limiter/config.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/my_limiter/wsgi.py b/my_limiter/wsgi.py index d139e82..61f01f3 100644 --- a/my_limiter/wsgi.py +++ b/my_limiter/wsgi.py @@ -1,3 +1,20 @@ +""" +TODO: implement leaky bucket + - in-app + - [x] in-memory + - [ ] redis + - [ ] redis cluster + - [ ] Flask middleware - https://flask.palletsprojects.com/en/2.1.x/quickstart/#hooking-in-wsgi-middleware + - [ ] NGINX - https://leandromoreira.com/2019/01/25/how-to-build-a-distributed-throttling-system-with-nginx-lua-redis/ + - https://www.nginx.com/blog/rate-limiting-nginx/ + - [ ] AWS API Gateway + - [ ] HAProxy Stick Tables - https://www.haproxy.com/blog/introduction-to-haproxy-stick-tables + - [ ] Cloudflare (Spectrum?) +TODO: implement fixed window counter +TODO: implement sliding window log +TODO: implement sliding window counter +TODO: use session IDs instead of IP address +""" import flask as f from . import algos