sqlalchemy_dlock.sessionlevellock module

class sqlalchemy_dlock.sessionlevellock.AbstractSessionLevelLock(connection_or_session: Union[sqlalchemy.engine.base.Connection, sqlalchemy.orm.session.Session, sqlalchemy.orm.scoping.scoped_session], key, **_)

Bases: _thread._local

Base class of database session level lock implementation

Note

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

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

Attention

The Session here means that of Database, NOT SQLAlchemy’s sqlalchemy.orm.session.Session, which is more like a transaction. Here we roughly take sqlalchemy.engine.Connection as database’s session.

The lock’s acquire() and release() methods can be used as context managers for a with statement. The acquire() method 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...

is equivalent to:

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

If do not want it to be locked automatically in with statement, contextlib.closing() maybe useful:

from contextlib import closing

with closing(some_lock):
    # not locked
    some_lock.acquire()
    # locked
pass
# un-locked automatically
Parameters
  • connection_or_session (sqlalchemy Connection or orm Session/ScopedSession object.) – SQL locking functions will be invoked on it

  • key – ID or name used as SQL locking function’s key

acquire(block: bool = True, timeout: Optional[Union[float, int]] = None, **kwargs) bool

Acquire a lock, blocking or non-blocking.

  • With the block argument set to True (the default), the method call will block until the lock is in an unlocked state, then set it to locked and return True.

  • With the block argument set to False, the method call does not block. If the lock is currently in a locked state, return False; otherwise set the lock to a locked state and return True.

  • When invoked with a positive, floating-point value for timeout, block for at most the number of seconds specified by timeout as long as the lock can not be acquired. Invocations with a negative value for timeout are equivalent to a timeout of zero. Invocations with a timeout value of None (the default) set the timeout period to infinite. The timeout argument has no practical implications if the block argument is set to False and is thus ignored. Returns True if the lock has been acquired or False if the timeout period has elapsed.

property acquired: bool

locked/unlocked state property

As a Getter: it returns True if the lock has been acquired, False otherwise.

As a Setter:

  • Set to True is equivalent to call acquire()

  • Set to False is equivalent to call release()

close(**kwargs)

Same as release()

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

An invocation of this method is equivalent to:

if not some_lock.acquired:
    some_lock.release()

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

eg:

# ...

from contextlib import closing
from sqlalchemy_dlock import sadlock

# ...

with closing(sadlock(some_connection, some_key)) as lock:
    # will not acquire at the begin of with-block
    assert not lock.acquired
    # ...
    # lock when need
    lock.acquire()
    assert lock.acquired
    # ...
# `close` will be called at the end with-block
assert not lock.acquired
property connection_or_session: Union[sqlalchemy.engine.base.Connection, sqlalchemy.orm.session.Session, sqlalchemy.orm.scoping.scoped_session]

Returns connection_or_session parameter of the constructor

property key

Returns key parameter of the constructor

property locked: bool

Alias of acquired

release(**kwargs)

Release a lock.

Since the class is thread-local, this cannot be called from other thread or process, and also can not be called from other connection (PostgreSQL’s shared advisory lock supports so, but we haven’t).

When the lock is locked, reset it to unlocked, and return. If any other threads are blocked waiting for the lock to become unlocked, allow exactly one of them to proceed.

When invoked on an unlocked lock, a ValueError is raised.

There is no return value.