Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 15 additions & 7 deletions pottery/aioredlock.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
from typing import ClassVar
from typing import Iterable
from typing import Type
from typing import Union

from redis import RedisError
from redis.asyncio import Redis as AIORedis
Expand Down Expand Up @@ -150,15 +151,15 @@ class AIORedlock(Scripts, AIOPrimitive):
_AUTO_RELEASE_TIME: ClassVar[float] = Redlock._AUTO_RELEASE_TIME
_CLOCK_DRIFT_FACTOR: ClassVar[float] = Redlock._CLOCK_DRIFT_FACTOR
_RETRY_DELAY: ClassVar[float] = Redlock._RETRY_DELAY
_NUM_EXTENSIONS: ClassVar[int] = Redlock._NUM_EXTENSIONS
_NUM_EXTENSIONS: ClassVar[Union[int, float]] = Redlock._NUM_EXTENSIONS

def __init__(self,
*,
key: str,
masters: Iterable[AIORedis],
raise_on_redis_errors: bool = False,
auto_release_time: float = _AUTO_RELEASE_TIME,
num_extensions: int = _NUM_EXTENSIONS,
num_extensions: Union[int, float] = _NUM_EXTENSIONS,
context_manager_blocking: bool = True,
context_manager_timeout: float = -1,
) -> None:
Expand All @@ -173,8 +174,8 @@ def __init__(self,
auto_release_time -- the timeout in seconds by which to
automatically release this AIORedlock, unless it's already been
released
num_extensions -- the number of times that this AIORedlock's lease
can be extended
num_extensions -- the number of times that this Redlock's lease can be extended.
Value can be either a positive integer or float infinity (math.inf)
context_manager_blocking -- when using this AIORedlock as a context
manager, whether to block when acquiring
context_manager_timeout -- if context_manager_blocking, how long to
Expand All @@ -183,7 +184,9 @@ def __init__(self,
'''
if not context_manager_blocking and context_manager_timeout != -1:
raise ValueError("can't specify a timeout for a non-blocking call")

if num_extensions < 0 or (isinstance(num_extensions, float) and not math.isinf(num_extensions)):
raise ValueError("num_extensions must be either a positive integer or float infinity")

super().__init__(
key=key,
masters=masters,
Expand All @@ -196,6 +199,10 @@ def __init__(self,
self._uuid = ''
self._extension_num = 0

@property
def limited_extensions(self) -> bool:
return not math.isinf(self.num_extensions)

# Preserve the Open-Closed Principle with name mangling.
# https://youtu.be/miGolgp9xq8?t=2086
# https://stackoverflow.com/a/38534939
Expand Down Expand Up @@ -450,7 +457,7 @@ async def extend(self,
9
10
'''
if self._extension_num >= self.num_extensions:
if self.limited_extensions and self._extension_num >= self.num_extensions:
raise TooManyExtensions(self.key, self.masters)

num_masters_extended, redis_errors = 0, []
Expand All @@ -466,7 +473,8 @@ async def extend(self,
error.__class__.__qualname__,
)
if num_masters_extended > len(self.masters) // 2:
self._extension_num += 1
if self.limited_extensions:
self._extension_num += 1
return

self._check_enough_masters_up(raise_on_redis_errors, redis_errors)
Expand Down
28 changes: 17 additions & 11 deletions pottery/redlock.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
from typing import Literal
from typing import Tuple
from typing import Type
from typing import Union
from typing import cast
from typing import overload

Expand Down Expand Up @@ -229,15 +230,15 @@ class Redlock(Scripts, Primitive):
_AUTO_RELEASE_TIME: ClassVar[float] = 10
_CLOCK_DRIFT_FACTOR: ClassVar[float] = 0.01
_RETRY_DELAY: ClassVar[float] = .2
_NUM_EXTENSIONS: ClassVar[int] = 3
_NUM_EXTENSIONS: ClassVar[Union[int, float]] = 3

def __init__(self,
*,
key: str,
masters: Iterable[Redis] = frozenset(),
raise_on_redis_errors: bool = False,
auto_release_time: float = _AUTO_RELEASE_TIME,
num_extensions: int = _NUM_EXTENSIONS,
num_extensions: Union[int, float] = _NUM_EXTENSIONS,
context_manager_blocking: bool = True,
context_manager_timeout: float = -1,
) -> None:
Expand All @@ -252,8 +253,8 @@ def __init__(self,
auto_release_time -- the timeout in seconds by which to
automatically release this Redlock, unless it's already been
released
num_extensions -- the number of times that this Redlock's lease can
be extended
num_extensions -- the number of times that this Redlock's lease can be extended.
Value can be either a positive integer or float infinity (math.inf)
context_manager_blocking -- when using this Redlock as a context
manager, whether to block when acquiring
context_manager_timeout -- if context_manager_blocking, how long to
Expand All @@ -262,7 +263,9 @@ def __init__(self,
'''
if not context_manager_blocking and context_manager_timeout != -1:
raise ValueError("can't specify a timeout for a non-blocking call")

if num_extensions < 0 or (isinstance(num_extensions, float) and not math.isinf(num_extensions)):
raise ValueError("num_extensions must be either a positive integer or float infinity")

super().__init__(
key=key,
masters=masters,
Expand All @@ -275,6 +278,10 @@ def __init__(self,
self._uuid = ''
self._extension_num = 0

@property
def limited_extensions(self) -> bool:
return not math.isinf(self.num_extensions)

def __acquire_master(self, master: Redis) -> bool:
acquired = master.set(
self.key,
Expand Down Expand Up @@ -520,7 +527,7 @@ def extend(self, *, raise_on_redis_errors: bool | None = None) -> None:
True
>>> printer_lock.release()
'''
if self._extension_num >= self.num_extensions:
if self.limited_extensions and self._extension_num >= self.num_extensions:
raise TooManyExtensions(self.key, self.masters)

with BailOutExecutor() as executor:
Expand All @@ -542,7 +549,8 @@ def extend(self, *, raise_on_redis_errors: bool | None = None) -> None:
)
else:
if num_masters_extended > len(self.masters) // 2:
self._extension_num += 1
if self.limited_extensions:
self._extension_num += 1
return

self._check_enough_masters_up(raise_on_redis_errors, redis_errors)
Expand Down Expand Up @@ -699,11 +707,9 @@ def synchronize(*,
exception when too many Redis masters throw errors
auto_release_time -- the timeout in seconds by which to automatically
release this Redlock, unless it's already been released
num_extensions -- the number of times that this Redlock's lease can be
extended
context_manager_blocking -- when using this Redlock as a context
blocking -- when using this Redlock as a context
manager, whether to block when acquiring
context_manager_timeout -- if context_manager_blocking, how long to wait
timeout -- if context_manager_blocking, how long to wait
when acquiring before giving up and raising the QuorumNotAchieved
exception

Expand Down