Skip to content

Synchronization

grelmicro.sync

Synchronization.

LeaderElection

LeaderElection(
    name: str,
    *,
    backend: SyncBackend | str | None = None,
    worker: str | UUID | None = None,
    lease_duration: Seconds | None = None,
    renew_deadline: Seconds | None = None,
    retry_interval: Seconds | None = None,
    backend_timeout: Seconds | None = None,
    error_interval: Seconds | None = None,
    env_prefix: str | None = None,
    read_env: bool = True,
)

Bases: SyncPrimitive, Task

Leader Election.

The leader election is a synchronization primitive with the worker as scope. It runs as a task to acquire or renew the distributed lock.

Initialize the leader election.

PARAMETER DESCRIPTION
name

The name of the resource representing the leader election.

It will be used as the lock name so make sure it is unique on the distributed lock backend.

TYPE: str

backend

The distributed lock backend used to acquire and release the lock.

By default, it will use the lock backend registry to get the default lock backend.

TYPE: SyncBackend | str | None DEFAULT: None

worker

The worker identity.

By default, a UUIDv1 will be generated.

TYPE: str | UUID | None DEFAULT: None

lease_duration

The duration in seconds after the lock will be released if not renewed.

Default: 15. If the worker becomes unavailable, the lock can only be acquired by an other worker after it has expired. When unset, resolves from the environment variable GREL_LEADER_ELECTION_{NAME_UPPER}_LEASE_DURATION if present, otherwise falls back to the LeaderElectionConfig default.

TYPE: Seconds | None DEFAULT: None

renew_deadline

The duration in seconds that the leader worker will try to acquire the lock before giving up.

Default: 10. Must be shorter than the lease duration. In case of multiple errors, the leader worker will lose the lead to prevent split-brain scenarios and ensure that only one worker is the leader at any time.

TYPE: Seconds | None DEFAULT: None

retry_interval

The duration in seconds between attempts to acquire or renew the lock.

Default: 2. Must be shorter than the renew deadline. A shorter schedule enables faster leader elections but may increase load on the distributed lock backend, while a longer schedule reduces load but can delay new leader elections.

TYPE: Seconds | None DEFAULT: None

backend_timeout

The duration in seconds for waiting on backend for acquiring and releasing the lock.

Default: 5. This value determines how long the system will wait before giving up the current operation.

TYPE: Seconds | None DEFAULT: None

error_interval

The duration in seconds between logging error messages.

Default: 30. If shorter than the retry interval, it will log every error. It is used to prevent flooding the logs when the lock backend is unavailable.

TYPE: Seconds | None DEFAULT: None

env_prefix

Override the auto-derived environment variable prefix.

Default: GREL_LEADER_ELECTION_{NAME_UPPER}_. Set this to a custom prefix when the application uses a different naming convention.

TYPE: str | None DEFAULT: None

read_env

Whether to read environment variables.

Default: True. Set to False when every field is already supplied via kwargs and the environment must not influence construction.

TYPE: bool DEFAULT: True

config property

config: LeaderElectionConfig

Return the leader election config.

name property

name: str

Return the task name.

backend property

backend: SyncBackend

Bound sync backend, resolved on each call.

When a backend instance was passed at construction it is always returned. Otherwise the registry is consulted on every access so that task-scoped sync.use(...) overrides take effect.

from_config classmethod

from_config(
    name: str,
    config: LeaderElectionConfig,
    *,
    backend: SyncBackend | str | None = None,
) -> Self

Construct a LeaderElection from a name and a pre-built LeaderElectionConfig.

PARAMETER DESCRIPTION
name

The name of the resource representing the leader election.

Acts as the instance identity. Used as the backend lock key and exposed via the name property.

TYPE: str

config

The pre-built leader election configuration.

Use this path when the configuration is assembled at startup from a settings tree (for example YAML, Vault, or a pydantic-settings aggregator). The environment path is bypassed and the config is used as-is.

TYPE: LeaderElectionConfig

backend

The distributed lock backend used to acquire and release the lock.

By default, it will use the lock backend registry to get the default lock backend.

TYPE: SyncBackend | str | None DEFAULT: None

is_running

is_running() -> bool

Check if the leader election task is running.

is_leader

is_leader() -> bool

Check if the current worker is the leader.

To avoid a split-brain scenario, the leader considers itself as no longer leader if the renew deadline is reached.

RETURNS DESCRIPTION
bool

True if the current worker is the leader, False otherwise.

wait_for_leader async

wait_for_leader() -> None

Wait until the current worker is the leader.

wait_lose_leader async

wait_lose_leader() -> None

Wait until the current worker is no longer the leader.

guard

guard() -> _LeaderGuard

Return a non-blocking synchronization guard.

The guard raises WouldBlock if the current worker is not the leader, making it suitable for use as the sync parameter of IntervalTask.

Unlike using LeaderElection directly (which blocks until leader), the guard skips the current tick and retries on the next interval.

Lock

Lock(
    name: str,
    *,
    backend: SyncBackend | str | None = None,
    worker: str | UUID | None = None,
    lease_duration: Seconds | None = None,
    retry_interval: Seconds | None = None,
    env_prefix: str | None = None,
    read_env: bool = True,
)

Bases: BaseLock

Lock.

This lock is a distributed lock that is used to acquire a resource across multiple workers. The lock is acquired asynchronously and can be extended multiple times manually. The lock is automatically released after a duration if not extended.

Initialize the lock.

PARAMETER DESCRIPTION
name

The name of the resource to lock.

It will be used as the lock name so make sure it is unique on the lock backend.

TYPE: str

backend

The distributed lock backend used to acquire and release the lock.

Accepts a backend instance, the name of a registered backend (e.g. "analytics"), or None to use the registered "default" backend.

TYPE: SyncBackend | str | None DEFAULT: None

worker

The worker identity.

By default, a UUIDv1 is generated.

TYPE: str | UUID | None DEFAULT: None

lease_duration

The duration in seconds for the lock to be held by default.

Default: 60. When unset, resolves from the environment variable GREL_LOCK_{NAME_UPPER}_LEASE_DURATION if present, otherwise falls back to the LockConfig default.

TYPE: Seconds | None DEFAULT: None

retry_interval

The duration in seconds between attempts to acquire the lock.

Default: 0.1. Must be >= 0.001 to prevent flooding the lock backend. When unset, resolves from the environment variable GREL_LOCK_{NAME_UPPER}_RETRY_INTERVAL if present, otherwise falls back to the LockConfig default.

TYPE: Seconds | None DEFAULT: None

env_prefix

Override the auto-derived environment variable prefix.

Default: GREL_LOCK_{NAME_UPPER}_. Set this to a custom prefix when the application uses a different naming convention, for example MYAPP_LOCK_CART_.

TYPE: str | None DEFAULT: None

read_env

Whether to read environment variables.

Default: True. Set to False when every field is already supplied via kwargs and the environment must not influence construction.

TYPE: bool DEFAULT: True

name property

name: str

Return the lock identity.

backend property

backend: SyncBackend

Bound sync backend, resolved on each call.

When a backend instance was passed at construction it is always returned. Otherwise the registry is consulted on every access so that task-scoped sync.use(...) overrides take effect.

config property

config: LockConfig

Return the lock config.

from_thread property

from_thread: ThreadLockAdapter

Return the lock adapter for worker thread.

from_config classmethod

from_config(
    name: str,
    config: LockConfig,
    *,
    backend: SyncBackend | str | None = None,
) -> Self

Construct a Lock from a name and a pre-built LockConfig.

PARAMETER DESCRIPTION
name

The name of the resource to lock.

Acts as the instance identity. Used as the backend lock key and exposed via the name property.

TYPE: str

config

The pre-built lock configuration.

Use this path when the configuration is assembled at startup from a settings tree (for example YAML, Vault, or a pydantic-settings aggregator). The environment path is bypassed and the config is used as-is.

TYPE: LockConfig

backend

The distributed lock backend used to acquire and release the lock.

Accepts a backend instance, the name of a registered backend (e.g. "analytics"), or None to use the registered "default" backend.

TYPE: SyncBackend | str | None DEFAULT: None

acquire async

acquire() -> None

Acquire the lock.

RAISES DESCRIPTION
LockReentrantError

If the lock is already acquired (nested usage is not supported).

LockAcquireError

If the lock cannot be acquired due to an error on the backend.

acquire_nowait async

acquire_nowait() -> None

Acquire the lock, without blocking.

RAISES DESCRIPTION
LockReentrantError

If the lock is already acquired (nested usage is not supported).

WouldBlock

If the lock cannot be acquired without blocking.

LockAcquireError

If the lock cannot be acquired due to an error on the backend.

release async

release() -> None

Release the lock.

RAISES DESCRIPTION
LockNotOwnedError

If the lock is not owned by the current token.

LockReleaseError

If the lock cannot be released due to an error on the backend.

locked async

locked() -> bool

Check if the lock is acquired.

RAISES DESCRIPTION
LockLockedCheckError

If the lock cannot be checked due to an error on the backend.

owned async

owned() -> bool

Check if the lock is owned by the current token.

RAISES DESCRIPTION
SyncBackendError

If the lock cannot be checked due to an error on the backend.

do_acquire async

do_acquire(token: str) -> bool

Acquire the lock.

This method should not be called directly. Use acquire instead.

RETURNS DESCRIPTION
bool

True if the lock was acquired, False if the lock was not acquired.

TYPE: bool

RAISES DESCRIPTION
LockAcquireError

If the lock cannot be acquired due to an error on the backend.

do_release async

do_release(token: str) -> bool

Release the lock.

This method should not be called directly. Use release instead.

RETURNS DESCRIPTION
bool

True if the lock was released, False otherwise.

TYPE: bool

RAISES DESCRIPTION
LockReleaseError

Cannot release the lock due to backend error.

do_owned async

do_owned(token: str) -> bool

Check if the lock is owned by the current token.

This method should not be called directly. Use owned instead.

RETURNS DESCRIPTION
bool

True if the lock is owned by the current token, False otherwise.

TYPE: bool

RAISES DESCRIPTION
LockOwnedCheckError

Cannot check if the lock is owned due to backend error.

do_thread_acquire async

do_thread_acquire(thread_id: int) -> None

Acquire the lock from a worker thread (blocking).

Runs on the event loop so the reentrant check and backend acquire are atomic with respect to other threads.

RAISES DESCRIPTION
LockReentrantError

If the lock is already acquired (nested usage is not supported).

LockAcquireError

If the lock cannot be acquired due to an error on the backend.

do_thread_acquire_nowait async

do_thread_acquire_nowait(thread_id: int) -> None

Acquire the lock from a worker thread (non-blocking).

Runs on the event loop so the reentrant check and backend acquire are atomic with respect to other threads.

RAISES DESCRIPTION
LockReentrantError

If the lock is already acquired (nested usage is not supported).

WouldBlock

If the lock cannot be acquired without blocking.

LockAcquireError

If the lock cannot be acquired due to an error on the backend.

do_thread_release async

do_thread_release(thread_id: int) -> None

Release the lock from a worker thread.

Runs on the event loop so the backend release is atomic with respect to other threads.

RAISES DESCRIPTION
LockNotOwnedError

If the lock is not owned by the current token.

LockReleaseError

If the lock cannot be released due to an error on the backend.

SyncError

Bases: GrelmicroError

Synchronization Primitive Error.

This is the base class for all synchronization errors.

SyncPrimitive

Bases: Protocol

Synchronization Primitive Protocol.

SyncSettingsValidationError

SyncSettingsValidationError(error: ValidationError | str)

Bases: SyncError, SettingsValidationError

Synchronization Settings Validation Error.

TaskLock

TaskLock(
    name: str,
    *,
    backend: SyncBackend | str | None = None,
    worker: str | UUID | None = None,
    min_lock_seconds: Seconds | None = None,
    max_lock_seconds: Seconds | None = None,
    env_prefix: str | None = None,
    read_env: bool = True,
)

Bases: SyncPrimitive

Task Lock.

A distributed lock for scheduled tasks. Unlike a regular Lock, TaskLock does not release immediately on context manager exit. Instead, it keeps the lock held for at least min_lock_seconds seconds to prevent re-execution on other nodes.

There is no background task that maintains the lock active during execution. The lock relies entirely on the TTL (max_lock_seconds) set at acquire time.

This lock is designed to be used as the sync parameter of IntervalTask.

Initialize the task lock.

PARAMETER DESCRIPTION
name

The name of the resource to lock.

It will be used as the lock name so make sure it is unique on the lock backend.

TYPE: str

backend

The distributed lock backend used to acquire and release the lock.

By default, it will use the lock backend registry to get the default lock backend.

TYPE: SyncBackend | str | None DEFAULT: None

worker

The worker identity.

By default, a UUIDv1 is generated.

TYPE: str | UUID | None DEFAULT: None

min_lock_seconds

The minimum duration in seconds to hold the lock after task completion.

Default: 1. Prevents re-execution on other nodes before this duration has elapsed. When unset, resolves from the environment variable GREL_TASK_LOCK_{NAME_UPPER}_MIN_LOCK_SECONDS if present, otherwise falls back to the TaskLockConfig default.

TYPE: Seconds | None DEFAULT: None

max_lock_seconds

The maximum duration in seconds to hold the lock (deadlock protection).

Default: 60. Acts as the TTL on acquire. When unset, resolves from the environment variable GREL_TASK_LOCK_{NAME_UPPER}_MAX_LOCK_SECONDS if present, otherwise falls back to the TaskLockConfig default.

TYPE: Seconds | None DEFAULT: None

env_prefix

Override the auto-derived environment variable prefix.

Default: GREL_TASK_LOCK_{NAME_UPPER}_. Set this to a custom prefix when the application uses a different naming convention.

TYPE: str | None DEFAULT: None

read_env

Whether to read environment variables.

Default: True. Set to False when every field is already supplied via kwargs and the environment must not influence construction.

TYPE: bool DEFAULT: True

name property

name: str

Return the task lock identity.

backend property

backend: SyncBackend

Bound sync backend, resolved on each call.

When a backend instance was passed at construction it is always returned. Otherwise the registry is consulted on every access so that task-scoped sync.use(...) overrides take effect.

config property

config: TaskLockConfig

Return the task lock config.

from_thread property

from_thread: ThreadTaskLockAdapter

Return the task lock adapter for worker thread.

from_config classmethod

from_config(
    name: str,
    config: TaskLockConfig,
    *,
    backend: SyncBackend | str | None = None,
) -> Self

Construct a TaskLock from a name and a pre-built TaskLockConfig.

PARAMETER DESCRIPTION
name

The name of the resource to lock.

Acts as the instance identity. Used as the backend lock key and exposed via the name property.

TYPE: str

config

The pre-built task lock configuration.

Use this path when the configuration is assembled at startup from a settings tree (for example YAML, Vault, or a pydantic-settings aggregator). The environment path is bypassed and the config is used as-is.

TYPE: TaskLockConfig

backend

The distributed lock backend used to acquire and release the lock.

By default, it will use the lock backend registry to get the default lock backend.

TYPE: SyncBackend | str | None DEFAULT: None

locked async

locked() -> bool

Check if the lock is acquired.

RAISES DESCRIPTION
LockLockedCheckError

If the lock cannot be checked due to an error on the backend.

do_acquire async

do_acquire(token: str) -> bool

Acquire the lock.

This method should not be called directly. Use the context manager instead.

RETURNS DESCRIPTION
bool

True if the lock was acquired, False if the lock was not acquired.

TYPE: bool

RAISES DESCRIPTION
LockAcquireError

If the lock cannot be acquired due to an error on the backend.

do_release async

do_release(token: str) -> bool

Release the lock.

This method should not be called directly. Use the context manager instead.

RETURNS DESCRIPTION
bool

True if the lock was released, False otherwise.

TYPE: bool

RAISES DESCRIPTION
LockReleaseError

Cannot release the lock due to backend error.

do_reacquire async

do_reacquire(token: str, duration: float) -> bool

Re-acquire the lock with a specific duration.

This method should not be called directly. Use the context manager instead.

RETURNS DESCRIPTION
bool

True if the lock was re-acquired, False otherwise.

TYPE: bool

RAISES DESCRIPTION
LockReleaseError

Cannot re-acquire the lock due to backend error.

do_thread_enter async

do_thread_enter() -> None

Acquire the lock from a worker thread.

Runs entirely on the event loop so the reentrant check, token generation, and backend acquire are atomic with respect to other threads.

RAISES DESCRIPTION
WouldBlock

If the lock is already held by another worker.

LockAcquireError

If the lock cannot be acquired due to a backend error.

LockReentrantError

If the lock is already acquired (nested usage is not supported).

do_thread_exit async

do_thread_exit() -> None

Release or extend the lock from a worker thread.

Runs entirely on the event loop so the token generation and backend release are atomic with respect to other threads.

RAISES DESCRIPTION
LockReleaseError

If the lock cannot be released due to a backend error.

do_exit async

do_exit(token: str) -> None

Handle exit logic: release or re-acquire based on elapsed time.