Пример #1
0
class RedisLock(Lock):
    def __init__(self, namespace='lock', **redis_kwargs):
        import redis
        from redis.sentinel import Sentinel
        redis_kwargs['decode_responses'] = True
        if redis_kwargs.get('sentinel') and redis_kwargs.get(
                'sentinel_service'):
            sentinels = [
                tuple(l.split(':'))
                for l in redis_kwargs.pop('sentinel').split(',')
            ]
            sentinel_service = redis_kwargs.pop('sentinel_service')
            kwargs = {
                k: v
                for k, v in redis_kwargs.items() if k in
                ["decode_responses", "password", "db", "socket_timeout"]
            }
            self._redis = Sentinel(sentinels,
                                   **kwargs).master_for(sentinel_service)
        else:
            kwargs = {
                k: v
                for k, v in redis_kwargs.items() if "sentinel" not in k
            }
            self._redis = redis.Redis(**kwargs)
        self._redis.ping()
        self._namespace = namespace
        info("Created redis lock manager with socket_timeout of {}s".format(
            redis_kwargs['socket_timeout']))

    def __key(self, name):
        return "{}:{}".format(self._namespace, name)

    def lock(self, name, owner, expiration=1, allow_owner_relock=False):
        """
        Obtain the named lock.
        :param allow_owner_relock: bool
        :param name: str the name of the lock
        :param owner: str a unique name for the locking node
        :param expiration: int in seconds, 0 expiration means forever
        """
        import redis

        try:
            if int(expiration) < 1:
                expiration = 1

            key = self.__key(name)
            non_existing = not (allow_owner_relock
                                and self._redis.get(key) == owner)
            return self._redis.set(key,
                                   owner,
                                   ex=int(expiration),
                                   nx=non_existing)
        except redis.exceptions.ResponseError as e:
            exception(
                "Unable to obtain lock, local state: name: %s, owner: %s, expiration: %s, allow_owner_relock: %s",
                name, owner, expiration, allow_owner_relock)

    def unlock(self, name, owner):
        """
        Release the named lock.
        :param name: str the name of the lock
        :param owner: str a unique name for the locking node
        """
        key = self.__key(name)
        if self._redis.get(key) == owner:
            self._redis.delete(key)
            return True
        return False

    def check_lock(self, name):
        return self._redis.get(self.__key(name)) is not None

    def print_locks(self):
        keys = self._redis.keys(self.__key('*'))
        for key in keys:
            print("{} locked by {}, expires in {} seconds".format(
                key, self._redis.get(key), self._redis.ttl(key)))