@contextmanager
    def lock(self, lock_key, expire=None, blocking_timeout=3, nowait=False):
        """
        Returns a context for locking a redis lock with the given key

        Args:
            lock_key (string): key to lock
            expire (float): how long (in seconds) we can hold lock before it is
                            automatically released
            blocking_timeout (float): how long (in seconds) to try locking until we give up.
            nowait (bool): if True, don't block if can't acquire the lock
                           (will instead raise an exception)
        """
        conn = self.redis

        if expire is None:
            expire = blocking_timeout

        delay = 0.01 + random() / 10
        lock = conn.lock(lock_key, timeout=expire, sleep=delay)
        acquired = lock.acquire(blocking=not nowait, blocking_timeout=blocking_timeout)
        # This is likely slightly after it was actually acquired, but it avoids reporting blocked
        # time as time spent holding the lock.
        start = time.time()

        self.logger.info('Acquiring lock on %s', lock_key)

        if not acquired:
            raise UnableToGetLock('Unable to fetch lock on %s' % (lock_key,))

        try:
            yield
        finally:
            self.logger.info('Releasing lock on %s', lock_key)

            try:
                lock.release()
            except Exception:
                # notably, an exception is raised if we release a lock we don't
                # own, e.g. because it expired while we held it.
                self.logger.exception("Error releasing lock %s acquired around %ss ago", lock_key, time.time() - start)
dataset/ETHPy150Open dropbox/changes/changes/ext/redis.py/_Redis.lock/original