asyncutils.altlocks

Non-conventional asynchronous synchronization primitives that may not adhere to the traditional lock interface.

Classes

CircuitBreaker

DynamicThrottle

Limit the rate of a function being called.

Releasing

Essentially invert the roles of the async enter and exit methods of a lock.

ResourceGuard

A sync- and async-compatible context manager, inspired by anyio.ResourceGuard, which causes contention of a shared resource to fail fast.

StatefulBarrier

An async barrier, that unlike traditional barriers, accumulates state from parties in a deque and makes it available once the barrier is tripped.

UniqueResourceGuard

A subclass of ResourceGuard that only allows one guard per object. Cannot be further subclassed.

Module Contents

class asyncutils.altlocks.CircuitBreaker[source]
The circuit breaker pattern. Use on async functions that may fail often, such as requests to an unreliable server.
Instances can be used as decorators, unless instantiated with a function as the first parameter, in which case the decorated function is returned.
Construct a circuit breaker, whose circuit is initially closed.
If name is passed, use it as its name; return a function wrapping f otherwise, deriving the name of the circuit breaker from the function. This derivation follows exactly one level of __wrapped__-based wrapping after retrieving the __func__ attribute if present.
Pass exceptions that are expected to happen through the exc parameter.
When the decorated function fails more than max_fails times (default CIRCUIT_BREAKER_DEFAULT_MAX_FAILS), the breaker triggers (opens the circuit, so to say) and disallows further calls of the wrapped functions by throwing an exception.
This state persists until the reset timeout expires (default CIRCUIT_BREAKER_DEFAULT_RESET). Then, the breaker enters the half-open state.
If the function completes successfully when the breaker is half-open under max_half_open_calls (default CIRCUIT_BREAKER_DEFAULT_MAX_HALF_OPEN_CALLS) tries, the circuit closes automatically. Otherwise, the circuit reopens.
class State

Bases: enum.IntEnum

Enum where members are also (and must be) ints

Initialize self. See help(type(self)) for accurate signature.

CLOSED = 0

The closed state.

HALF_OPEN = 1

The half-open state.

OPEN = 2

The open state.

__call__[T, **P](
f: collections.abc.Callable[P, collections.abc.Awaitable[T]],
/,
*,
timer: asyncutils._internal.prots.Timer = ...,
default: T = ...,
) collections.abc.Callable[P, types.CoroutineType[Any, Any, T]][source]
Apply the circuit breaker to a function f returning an awaitable, and return a wrapper function with the same signature that strictly returns coroutines.
timer (default time.monotonic()) is used to get the current time to calculate the timeout.
If passed, default is returned if an expected exception is raised, also suppressing that exception.

Caution

Care should be taken when applying the same circuit breaker to multiple functions, as the calls counters will be shared.

property fails: int

Current count of consecutive failures.

property name: str

The name of the circuit breaker, to be shown in error messages.

property state: State

The current state of the circuit breaker.

class asyncutils.altlocks.DynamicThrottle(
init_rate: float,
min_rate: float = ...,
max_rate: float = ...,
window: int | None = ...,
*,
ubound: float | None = ...,
lbound: float | None = ...,
ufactor: float | None = ...,
lfactor: float | None = ...,
jitter: float | None = ...,
timer: asyncutils._internal.prots.Timer = ...,
rand: collections.abc.Callable[[float], float] = ...,
)[source]

Limit the rate of a function being called.

See also

RateLimited

AdvancedRateLimit

Classes that serve similar rate-limiting functionality.

async __aenter__() None[source]

Wait for the time as computed by the throttler, with some jitter applied, to pass, such that the rate is maintained.

async __aexit__(exc_typ: asyncutils._internal.prots.ExcType, exc_val: BaseException, exc_tb: types.TracebackType, /) None[source]
async __aexit__(exc_typ: None, exc_val: None, exc_tb: None, /) None

If an error caused the context manager, increment fails and re-raise; otherwise, increment successes. Also adjust the rate if necessary.

reset() None[source]

Reset the counts of successes and fails.

property ctime: ty_extensions.JustFloat

The current time as returned by timer.

property fails: int

Current number of failed calls. Reset periodically.

property jitter: float

The current jitter in calculating the wait time.

property rate: float

The current rate.

property successes: int

Current number of succeeded calls; reset periodically.

class asyncutils.altlocks.Releasing(lock: asyncutils._internal.prots.AsyncLockLike[object], /)[source]

Essentially invert the roles of the async enter and exit methods of a lock.

Instantiate the async context manager to release lock on entry and re-acquires it on exit.

async __aenter__() None[source]

Call the release method of the lock, awaiting if it returns a coroutine.

async __aexit__(exc_typ: asyncutils._internal.prots.ExcType, exc_val: BaseException, exc_tb: types.TracebackType, /) None[source]
async __aexit__(exc_typ: None, exc_val: None, exc_tb: None, /) None

Re-enter the lock, propagating errors.

class asyncutils.altlocks.ResourceGuard[T][source]

Bases: asyncutils.mixins.AsyncContextMixin[None]

A sync- and async-compatible context manager, inspired by anyio.ResourceGuard, which causes contention of a shared resource to fail fast.

Tip

A strong reference to the object will be held for the lifetime of the guard.

Note

The guard is not held upon creation.

action is used in error messages to describe the action being attempted on the resource, such as 'access' or 'close'.
rsrc is used in error messages to describe the resource by calling its __repr__(); if not passed, an index is automatically assigned to the resource.
__enter__() None[source]
Throw ResourceBusy if the resource is already being guarded.
Otherwise, mark the resource as guarded, such that guarded evaluates to True.
__exit__(exc_typ: asyncutils._internal.prots.ExcType, exc_val: BaseException, exc_tb: types.TracebackType, /) None[source]
__exit__(exc_typ: None, exc_val: None, exc_tb: None, /) None

Mark the resource as no longer guarded.

yields_resource() asyncutils._internal.prots.DualContextManager[T][source]

Return a one-off context manager serving the same purpose as the guard but giving the resource on entry.

property action: str

The action being attempted on the resource, as passed to the constructor. Should be a gerund.

property guarded: bool

Whether the resource is currently being guarded.

property success_ratio: float

The current ratio of successful acquisitions to total acquisition attempts, or 0.0 if there have been no attempts.

class asyncutils.altlocks.StatefulBarrier[T](parties: int, name: str = ..., *, max_state: int | None = ...)[source]
class asyncutils.altlocks.StatefulBarrier(
parties: int,
*,
init_state: asyncutils._internal.prots.SupportsIteration[T],
max_state: int | None = ...,
)
class asyncutils.altlocks.StatefulBarrier(
parties: int,
name: str,
init_state: asyncutils._internal.prots.SupportsIteration[T],
max_state: int | None = ...,
)

Bases: asyncutils.mixins.AwaitableMixin[tuple[int, collections.deque[T]]]

An async barrier, that unlike traditional barriers, accumulates state from parties in a deque and makes it available once the barrier is tripped.

  • parties (required): The number of parties required to break the barrier.

  • name: The name of the barrier, to appear in error messages.

  • init_state: An iterable storing the initial state. The iterable will be exhausted eventually.

  • max_state: Maximum length of state to store. Older state will be expelled.

async abort() None[source]

Abort the barrier, signalling BrokenBarrierError to present waiting parties.

raise_for_abort() None[source]

Throw BrokenBarrierError if the barrier has been aborted.

async wait(state: T = ..., timeout: float | None = ...) tuple[int, collections.deque[T]][source]
Note that the calling party is waiting for the barrier, optionally adding some state.
If the barrier has already been aborted or broken, raise BrokenBarrierError.
Once enough parties are waiting, all callers receive a tuple (pos, states), where states is the deque of stored state and pos the number of parties having arrived before this one.
property broken: bool

Whether the barrier is broken.

property n_waiting: int

Number of parties currently waiting.

property parties: int

Total number of parties, arrived or not.

property remaining_parties: int

Number of parties the waiting parties are waiting for.

class asyncutils.altlocks.UniqueResourceGuard[T: collections.abc.Hashable][source]

Bases: ResourceGuard[T]

A subclass of ResourceGuard that only allows one guard per object. Cannot be further subclassed.

Note

You must keep the guard alive for as long as you want the resource to be guarded.

Caution

This class does not stop the object from having an instance of ResourceGuard (or subclass thereof) from guarding it simultaneously.

Implementation detail

Instances are weakly referenceable.

If the object already has a guard, return that guard, regardless of whether it is held. In that case, the action parameter is ignored and a warning is issued.
Otherwise, create and return a new guard for the object, using the action parameter in error messages.

Attention

The error will be seen by the user only when they actually try to acquire the guard if it is already held.

classmethod clear_cache() None[source]

Clear the internal cache mapping guarded objects to their guards. Call only when you are sure no guards are in use.