|
24 | 24 | SSLConnection,
|
25 | 25 | parse_url,
|
26 | 26 | )
|
| 27 | +from redis.asyncio.lock import Lock |
27 | 28 | from redis.asyncio.parser import CommandsParser
|
28 | 29 | from redis.client import EMPTY_RESPONSE, NEVER_DECODE, AbstractRedis
|
29 | 30 | from redis.cluster import (
|
@@ -764,6 +765,72 @@ def pipeline(
|
764 | 765 |
|
765 | 766 | return ClusterPipeline(self)
|
766 | 767 |
|
| 768 | + def lock( |
| 769 | + self, |
| 770 | + name: KeyT, |
| 771 | + timeout: Optional[float] = None, |
| 772 | + sleep: float = 0.1, |
| 773 | + blocking_timeout: Optional[float] = None, |
| 774 | + lock_class: Optional[Type[Lock]] = None, |
| 775 | + thread_local: bool = True, |
| 776 | + ) -> Lock: |
| 777 | + """ |
| 778 | + Return a new Lock object using key ``name`` that mimics |
| 779 | + the behavior of threading.Lock. |
| 780 | +
|
| 781 | + If specified, ``timeout`` indicates a maximum life for the lock. |
| 782 | + By default, it will remain locked until release() is called. |
| 783 | +
|
| 784 | + ``sleep`` indicates the amount of time to sleep per loop iteration |
| 785 | + when the lock is in blocking mode and another client is currently |
| 786 | + holding the lock. |
| 787 | +
|
| 788 | + ``blocking_timeout`` indicates the maximum amount of time in seconds to |
| 789 | + spend trying to acquire the lock. A value of ``None`` indicates |
| 790 | + continue trying forever. ``blocking_timeout`` can be specified as a |
| 791 | + float or integer, both representing the number of seconds to wait. |
| 792 | +
|
| 793 | + ``lock_class`` forces the specified lock implementation. Note that as |
| 794 | + of redis-py 3.0, the only lock class we implement is ``Lock`` (which is |
| 795 | + a Lua-based lock). So, it's unlikely you'll need this parameter, unless |
| 796 | + you have created your own custom lock class. |
| 797 | +
|
| 798 | + ``thread_local`` indicates whether the lock token is placed in |
| 799 | + thread-local storage. By default, the token is placed in thread local |
| 800 | + storage so that a thread only sees its token, not a token set by |
| 801 | + another thread. Consider the following timeline: |
| 802 | +
|
| 803 | + time: 0, thread-1 acquires `my-lock`, with a timeout of 5 seconds. |
| 804 | + thread-1 sets the token to "abc" |
| 805 | + time: 1, thread-2 blocks trying to acquire `my-lock` using the |
| 806 | + Lock instance. |
| 807 | + time: 5, thread-1 has not yet completed. redis expires the lock |
| 808 | + key. |
| 809 | + time: 5, thread-2 acquired `my-lock` now that it's available. |
| 810 | + thread-2 sets the token to "xyz" |
| 811 | + time: 6, thread-1 finishes its work and calls release(). if the |
| 812 | + token is *not* stored in thread local storage, then |
| 813 | + thread-1 would see the token value as "xyz" and would be |
| 814 | + able to successfully release the thread-2's lock. |
| 815 | +
|
| 816 | + In some use cases it's necessary to disable thread local storage. For |
| 817 | + example, if you have code where one thread acquires a lock and passes |
| 818 | + that lock instance to a worker thread to release later. If thread |
| 819 | + local storage isn't disabled in this case, the worker thread won't see |
| 820 | + the token set by the thread that acquired the lock. Our assumption |
| 821 | + is that these cases aren't common and as such default to using |
| 822 | + thread local storage.""" |
| 823 | + if lock_class is None: |
| 824 | + lock_class = Lock |
| 825 | + return lock_class( |
| 826 | + self, |
| 827 | + name, |
| 828 | + timeout=timeout, |
| 829 | + sleep=sleep, |
| 830 | + blocking_timeout=blocking_timeout, |
| 831 | + thread_local=thread_local, |
| 832 | + ) |
| 833 | + |
767 | 834 |
|
768 | 835 | class ClusterNode:
|
769 | 836 | """
|
|
0 commit comments