Passed
Pull Request — master (#44)
by Paolo
05:38
created

common.tasks   A

Complexity

Total Complexity 6

Size/Duplication

Total Lines 76
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 6
eloc 26
dl 0
loc 76
rs 10
c 0
b 0
f 0

1 Function

Rating   Name   Duplication   Size   Complexity  
B redis_lock() 0 52 6
1
#!/usr/bin/env python3
2
# -*- coding: utf-8 -*-
3
"""
4
Created on Tue Jan 15 16:42:24 2019
5
6
@author: Paolo Cozzi <[email protected]>
7
"""
8
9
import redis
10
import logging
11
12
from contextlib import contextmanager
13
from celery.five import monotonic
14
15
from django.conf import settings
16
17
# Lock expires in 10 minutes
18
LOCK_EXPIRE = 60 * 10
19
20
# Get an instance of a logger
21
logger = logging.getLogger(__name__)
22
23
24
@contextmanager
25
def redis_lock(lock_id, blocking=False, expire=True):
26
    """
27
    This function get a lock relying on a lock name and other status. You
28
    can describe more process using the same lock name and give exclusive
29
    access to one of them.
30
31
    Args:
32
        lock_id (str): the name of the lock to take
33
        blocking (bool): if True, we wait until we have the block, if False
34
            we returns immediately False
35
        expire (bool): if True, lock will expire after LOCK_EXPIRE timeout,
36
            if False, it will persist until lock is released
37
38
    Returns:
39
        bool: True if lock acquired, False otherwise
40
    """
41
42
    # read parameters from settings
43
    REDIS_CLIENT = redis.StrictRedis(
44
        host=settings.REDIS_HOST,
45
        port=settings.REDIS_PORT,
46
        db=settings.REDIS_DB)
47
48
    # this will be the redis lock
49
    lock = None
50
51
    # timeout for the lock (if expire condition)
52
    timeout_at = monotonic() + LOCK_EXPIRE - 3
53
54
    if expire:
55
        lock = REDIS_CLIENT.lock(lock_id, timeout=LOCK_EXPIRE)
56
57
    else:
58
        lock = REDIS_CLIENT.lock(lock_id, timeout=None)
59
60
    status = lock.acquire(blocking=blocking)
61
62
    try:
63
        logger.debug("lock %s acquired is: %s" % (lock_id, status))
64
        yield status
65
66
    finally:
67
        # we take advantage of using add() for atomic locking
68
        # don't release the lock if we didn't acquire it
69
        if status and ((monotonic() < timeout_at and expire) or not expire):
70
            logger.debug("Releasing lock %s" % lock_id)
71
            # don't release the lock if we exceeded the timeout
72
            # to lessen the chance of releasing an expired lock
73
            # owned by someone else
74
            # if no timeout and lock is taken, release it
75
            lock.release()
76