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

common.tasks.redis_lock()   B

Complexity

Conditions 6

Size

Total Lines 52
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 18
dl 0
loc 52
rs 8.5666
c 0
b 0
f 0
cc 6
nop 3

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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