| 
28 | 28 |     TimeoutError,  | 
29 | 29 |     TryAgainError,  | 
30 | 30 | )  | 
 | 31 | +from redis.lock import Lock  | 
31 | 32 | from redis.utils import (  | 
32 | 33 |     dict_merge,  | 
33 | 34 |     list_keys_to_dict,  | 
@@ -227,6 +228,7 @@ class RedisCluster(RedisClusterCommands):  | 
227 | 228 |                 "ACL SETUSER",  | 
228 | 229 |                 "ACL USERS",  | 
229 | 230 |                 "ACL WHOAMI",  | 
 | 231 | +                "AUTH",  | 
230 | 232 |                 "CLIENT LIST",  | 
231 | 233 |                 "CLIENT SETNAME",  | 
232 | 234 |                 "CLIENT GETNAME",  | 
@@ -742,6 +744,72 @@ def pipeline(self, transaction=None, shard_hint=None):  | 
742 | 744 |             reinitialize_steps=self.reinitialize_steps,  | 
743 | 745 |         )  | 
744 | 746 | 
 
  | 
 | 747 | +    def lock(  | 
 | 748 | +        self,  | 
 | 749 | +        name,  | 
 | 750 | +        timeout=None,  | 
 | 751 | +        sleep=0.1,  | 
 | 752 | +        blocking_timeout=None,  | 
 | 753 | +        lock_class=None,  | 
 | 754 | +        thread_local=True,  | 
 | 755 | +    ):  | 
 | 756 | +        """  | 
 | 757 | +        Return a new Lock object using key ``name`` that mimics  | 
 | 758 | +        the behavior of threading.Lock.  | 
 | 759 | +
  | 
 | 760 | +        If specified, ``timeout`` indicates a maximum life for the lock.  | 
 | 761 | +        By default, it will remain locked until release() is called.  | 
 | 762 | +
  | 
 | 763 | +        ``sleep`` indicates the amount of time to sleep per loop iteration  | 
 | 764 | +        when the lock is in blocking mode and another client is currently  | 
 | 765 | +        holding the lock.  | 
 | 766 | +
  | 
 | 767 | +        ``blocking_timeout`` indicates the maximum amount of time in seconds to  | 
 | 768 | +        spend trying to acquire the lock. A value of ``None`` indicates  | 
 | 769 | +        continue trying forever. ``blocking_timeout`` can be specified as a  | 
 | 770 | +        float or integer, both representing the number of seconds to wait.  | 
 | 771 | +
  | 
 | 772 | +        ``lock_class`` forces the specified lock implementation. Note that as  | 
 | 773 | +        of redis-py 3.0, the only lock class we implement is ``Lock`` (which is  | 
 | 774 | +        a Lua-based lock). So, it's unlikely you'll need this parameter, unless  | 
 | 775 | +        you have created your own custom lock class.  | 
 | 776 | +
  | 
 | 777 | +        ``thread_local`` indicates whether the lock token is placed in  | 
 | 778 | +        thread-local storage. By default, the token is placed in thread local  | 
 | 779 | +        storage so that a thread only sees its token, not a token set by  | 
 | 780 | +        another thread. Consider the following timeline:  | 
 | 781 | +
  | 
 | 782 | +            time: 0, thread-1 acquires `my-lock`, with a timeout of 5 seconds.  | 
 | 783 | +                     thread-1 sets the token to "abc"  | 
 | 784 | +            time: 1, thread-2 blocks trying to acquire `my-lock` using the  | 
 | 785 | +                     Lock instance.  | 
 | 786 | +            time: 5, thread-1 has not yet completed. redis expires the lock  | 
 | 787 | +                     key.  | 
 | 788 | +            time: 5, thread-2 acquired `my-lock` now that it's available.  | 
 | 789 | +                     thread-2 sets the token to "xyz"  | 
 | 790 | +            time: 6, thread-1 finishes its work and calls release(). if the  | 
 | 791 | +                     token is *not* stored in thread local storage, then  | 
 | 792 | +                     thread-1 would see the token value as "xyz" and would be  | 
 | 793 | +                     able to successfully release the thread-2's lock.  | 
 | 794 | +
  | 
 | 795 | +        In some use cases it's necessary to disable thread local storage. For  | 
 | 796 | +        example, if you have code where one thread acquires a lock and passes  | 
 | 797 | +        that lock instance to a worker thread to release later. If thread  | 
 | 798 | +        local storage isn't disabled in this case, the worker thread won't see  | 
 | 799 | +        the token set by the thread that acquired the lock. Our assumption  | 
 | 800 | +        is that these cases aren't common and as such default to using  | 
 | 801 | +        thread local storage."""  | 
 | 802 | +        if lock_class is None:  | 
 | 803 | +            lock_class = Lock  | 
 | 804 | +        return lock_class(  | 
 | 805 | +            self,  | 
 | 806 | +            name,  | 
 | 807 | +            timeout=timeout,  | 
 | 808 | +            sleep=sleep,  | 
 | 809 | +            blocking_timeout=blocking_timeout,  | 
 | 810 | +            thread_local=thread_local,  | 
 | 811 | +        )  | 
 | 812 | + | 
745 | 813 |     def _determine_nodes(self, *args, **kwargs):  | 
746 | 814 |         command = args[0]  | 
747 | 815 |         nodes_flag = kwargs.pop("nodes_flag", None)  | 
 | 
0 commit comments