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:
|
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:
|
worker
|
The worker identity. By default, a UUIDv1 will be generated.
TYPE:
|
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
TYPE:
|
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:
|
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:
|
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:
|
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:
|
env_prefix
|
Override the auto-derived environment variable prefix. Default:
TYPE:
|
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:
|
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
TYPE:
|
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
TYPE:
|
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:
|
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:
|
backend
|
The distributed lock backend used to acquire and release the lock. Accepts a backend instance, the name of a registered backend
(e.g.
TYPE:
|
worker
|
The worker identity. By default, a UUIDv1 is generated.
TYPE:
|
lease_duration
|
The duration in seconds for the lock to be held by default. Default: 60. When unset, resolves from the environment
variable
TYPE:
|
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
TYPE:
|
env_prefix
|
Override the auto-derived environment variable prefix. Default:
TYPE:
|
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:
|
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
TYPE:
|
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
TYPE:
|
backend
|
The distributed lock backend used to acquire and release the lock. Accepts a backend instance, the name of a registered backend
(e.g.
TYPE:
|
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:
|
| 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:
|
| 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:
|
| 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)
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:
|
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:
|
worker
|
The worker identity. By default, a UUIDv1 is generated.
TYPE:
|
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
TYPE:
|
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
TYPE:
|
env_prefix
|
Override the auto-derived environment variable prefix. Default:
TYPE:
|
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:
|
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
TYPE:
|
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
TYPE:
|
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:
|
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:
|
| 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:
|
| 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:
|
| 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.