You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
76 lines
2.3 KiB
76 lines
2.3 KiB
|
3 years ago
|
import time
|
||
|
|
|
||
|
|
from deprecated.sphinx import deprecated
|
||
|
|
|
||
|
|
from limits.storage.memcached import MemcachedStorage
|
||
|
|
|
||
|
|
|
||
|
|
@deprecated(
|
||
|
|
reason="""The implementation has not been tested at all
|
||
|
|
in version 2.0 (and for many years) and will be removed in limits 2.5""",
|
||
|
|
version="2.0",
|
||
|
|
action="once",
|
||
|
|
)
|
||
|
|
class GAEMemcachedStorage(MemcachedStorage): # noqa
|
||
|
|
"""
|
||
|
|
rate limit storage with GAE memcache as backend
|
||
|
|
"""
|
||
|
|
|
||
|
|
MAX_CAS_RETRIES = 10
|
||
|
|
STORAGE_SCHEME = ["gaememcached"]
|
||
|
|
|
||
|
|
def __init__(self, uri: str, **options):
|
||
|
|
options["library"] = "google.appengine.api.memcache"
|
||
|
|
super().__init__(uri, **options)
|
||
|
|
|
||
|
|
def incr(
|
||
|
|
self, key: str, expiry: int, elastic_expiry: bool = False, amount: int = 1
|
||
|
|
):
|
||
|
|
"""
|
||
|
|
increments the counter for a given rate limit key
|
||
|
|
|
||
|
|
:param key: the key to increment
|
||
|
|
:param expiry: amount in seconds for the key to expire in
|
||
|
|
:param elastic_expiry: whether to keep extending the rate limit
|
||
|
|
window every hit.
|
||
|
|
:param amount: the number to increment by
|
||
|
|
"""
|
||
|
|
|
||
|
|
if not self.call_memcached_func(self.storage.add, key, amount, expiry):
|
||
|
|
if elastic_expiry:
|
||
|
|
# CAS id is set as state on the client object in GAE memcache
|
||
|
|
value = self.storage.gets(key)
|
||
|
|
retry = 0
|
||
|
|
|
||
|
|
while (
|
||
|
|
not self.call_memcached_func(
|
||
|
|
self.storage.cas, key, int(value or 0) + amount, expiry
|
||
|
|
)
|
||
|
|
and retry < self.MAX_CAS_RETRIES
|
||
|
|
):
|
||
|
|
value = self.storage.gets(key)
|
||
|
|
retry += 1
|
||
|
|
self.call_memcached_func(
|
||
|
|
self.storage.set, key + "/expires", expiry + time.time(), expiry
|
||
|
|
)
|
||
|
|
|
||
|
|
return int(value or 0) + amount
|
||
|
|
else:
|
||
|
|
return self.storage.incr(key, amount)
|
||
|
|
self.call_memcached_func(
|
||
|
|
self.storage.set, key + "/expires", expiry + time.time(), expiry
|
||
|
|
)
|
||
|
|
|
||
|
|
return 1
|
||
|
|
|
||
|
|
def check(self) -> bool:
|
||
|
|
"""
|
||
|
|
check if storage is healthy
|
||
|
|
"""
|
||
|
|
try:
|
||
|
|
self.call_memcached_func(self.storage.get_stats)
|
||
|
|
|
||
|
|
return True
|
||
|
|
except: # noqa
|
||
|
|
return False
|