Last active
April 5, 2020 14:18
-
-
Save Enforcer/51b2cb377f0cc11222e266a2ce94897c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
redis_connection = StrictRedis(host='redis') | |
# source: https://redis.io/topics/distlock | |
# This will be used to release lock IF AND ONLY IF we have acquired it | |
REMOVE_ONLY_IF_OWNER_SCRIPT = \ | |
"""if redis.call("get",KEYS[1]) == ARGV[1] then | |
return redis.call("del",KEYS[1]) | |
else | |
return 0 | |
end | |
""" | |
@contextmanager | |
def redis_lock(lock_name, expires=60): | |
# first, get a random value (for ownership) | |
random_value = str(uuid.uuid4()) | |
# execute SET {lock_name} {random_value} EX {expires} NX | |
lock_acquired = bool( | |
redis_connection.set(lock_name, random_value, ex=expires, nx=True) | |
) | |
logger.info(f'Lock acquired? {lock_name} for {expires} - {lock_acquired}') | |
yield lock_acquired | |
if lock_acquired: | |
# if lock was acquired, then try to release it BUT ONLY if we are the owner | |
# (i.e. value inside is identical to what we put there originally) | |
redis_connection.eval(REMOVE_ONLY_IF_OWNER_SCRIPT, 1, lock_name, random_value) | |
logger.info(f'Lock {lock_name} released!') | |
@app.task() | |
def periodic_task_with_lock(): | |
""" | |
This task uses redis_lock context manager to ensure it is executed | |
only one at a time. | |
""" | |
with redis_lock('periodic_task_with_lock_lock', 10) as acquired: | |
if not acquired: | |
# abort if one failed to acquire the lock | |
logger.warning('Lock not acquired!') | |
return | |
# ok, lock acquired! Work as usual... | |
will_sleep_for = randint(5, 8) | |
logger.info(f'I will keep lock for {will_sleep_for}s') | |
sleep(will_sleep_for) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment