sqlalchemy_dlock.lock.base module

class sqlalchemy_dlock.lock.base.AbstractLockMixin(*, key, convert=None, **kwargs)[source]

Bases: Generic[KeyTV, ActualKeyTV], ABC

Parameters:
  • key (KeyTV)

  • convert (Callable[[KeyTV], ActualKeyTV] | None)

property actual_key: ActualKeyTV
abstract get_actual_key()[source]
Return type:

TypeVar(ActualKeyTV)

class sqlalchemy_dlock.lock.base.BaseAsyncSadLock(connection_or_session, key, /, contextual_timeout=None, **kwargs)[source]

Bases: AbstractLockMixin, Generic[KeyTV, AsyncConnectionTV], _local, ABC

Async version of BaseSadLock

Parameters:
  • connection_or_session (AsyncConnectionTV)

  • key (KeyTV)

  • contextual_timeout (float | int | None)

abstract async acquire(block=True, timeout=None, *args, **kwargs)[source]
Return type:

bool

Parameters:
async close(*args, **kwargs)[source]
Return type:

None

property connection_or_session: AsyncConnectionTV
property key: KeyTV
property locked: bool
abstract async release(*args, **kwargs)[source]
Return type:

None

class sqlalchemy_dlock.lock.base.BaseSadLock(connection_or_session, key, /, contextual_timeout=None, **kwargs)[source]

Bases: AbstractLockMixin, Generic[KeyTV, ConnectionTV], _local, ABC

Base class of database lock implementation

Note

  • It’s Thread-Local (threading.local)

  • It’s an abstract class, do not manual instantiate

The acquire() and release() methods can be used as context managers for a with statement. acquire() will be called when the block is entered, and release() will be called when the block is exited. Hence, the following snippet:

with some_lock:
    # do something...
    pass

is equivalent to:

some_lock.acquire()
try:
    # do something...
    pass
finally:
    some_lock.release()

Note

A TimeoutError will be thrown if acquire timeout in with statement.

Parameters:
  • connection_or_session (TypeVar(ConnectionTV, bound= Union[Connection, Session, scoped_session])) – Connection or Session object SQL locking functions will be invoked on it

  • key (TypeVar(KeyTV)) – ID or name of the SQL locking function

  • contextual_timeout (Union[float, int, None]) –

    Timeout(seconds) for Context Managers.

    When called in a with statement, the new created lock object will pass it to timeout argument of BaseSadLock.acquire().

    Attention

    ONLY affects with statements.

    Example

    try:
        with create_sadlock(conn, k, contextual_timeout=5) as lck:
            # do something...
            pass
    except TimeoutError:
        # can not acquire after 5 seconds
        pass
    

    Note

    The default value of timeout is still None, when invoking acquire()

abstract acquire(block=True, timeout=None, *args, **kwargs)[source]

Acquire the lock in blocking or non-blocking mode.

The implementation should provide the following behavior: :rtype: bool

  • When block is True (the default), the method blocks until the lock is in an unlocked state, then sets it to locked and returns True.

  • When block is False, the method call is non-blocking. If the lock is currently locked, it returns False; otherwise, it sets the lock to locked state and returns True.

  • When invoked with a positive floating-point value for timeout, it blocks for at most the specified number of seconds until the lock can be acquired.

  • Invocations with a negative timeout value are equivalent to a timeout of zero.

  • When timeout is None (the default), the timeout period is infinite. The timeout parameter has no effect when block is False and is thus ignored.

  • Returns True if the lock has been acquired or False if the timeout period has elapsed.

Parameters:
Return type:

bool

close(*args, **kwargs)[source]

Same as release()

Except that the ValueError is NOT raised when invoked on an unlocked lock.

An invocation of this method is equivalent to:

if not some_lock.locked:
    some_lock.release()

This method maybe useful together with contextlib.closing(), when we need a with statement, but don’t want it to acquire at the beginning of the block. :rtype: None

Example

# ...

from contextlib import closing
from sqlalchemy_dlock import create_sadlock

# ...

with closing(create_sadlock(some_connection, some_key)) as lock:
    # will **NOT** acquire at the begin of with-block
    assert not lock.locked
    # ...
    # lock when need
    lock.acquire()
    assert lock.locked
    # ...

# `close` will be called at the end with-block
assert not lock.locked
Return type:

None

property connection_or_session: ConnectionTV

Connection or Session object SQL locking functions will be invoked on it

It returns connection_or_session parameter of the class’s constructor.

property key: KeyTV

ID or name of the SQL locking function

It returns key parameter of the class’s constructor

property locked: bool

locked/unlocked state property

True if the lock is acquired, else False

abstract release(*args, **kwargs)[source]

Release the lock.

Since the class is thread-local, this method cannot be called from another thread or process, nor can it be called from another connection. (Although PostgreSQL’s shared advisory lock supports this).

The implementation should provide the following behavior: :rtype: None

  • Reset the lock to unlocked state and return when the lock is currently locked.

  • Allow exactly one of any other threads blocked waiting for the lock to become unlocked to proceed.

  • Raise a ValueError when invoked on an unlocked lock.

  • Not return a value.

Return type:

None