postgresql-lock
Lock mechanism implemented with PostgreSQL advisory locks.
Easily implement distributed database locking.
Install
pip install postgresql-lock
Supported database interfaces
- asyncpg
- asynchronous
- psycopg2
- synchronous
- psycopg3
- asynchronous
- synchronous
- sqlalchemy (supports version 1 & 2; can use any underlying database interface)
- asynchronous
- synchronous
Why would I use this?
- PostgreSQL table locks aren't sufficient for your use-case
- PostgreSQL row locks don't work on
INSERT - You want to prevent race conditions between
INSERTandUPDATEon the same primary key - None of the aforementioned details fit your use-case, but you have PostgreSQL installed and need to prevent race conditions in a distributed system
Default operation
By default postgresql-lock will use session lock scope in blocking mode with
rollback_on_error enabled. The session lock scope means only a single database connection can
acquire the lock at a time.
Usage
All work revolves around the Lock class.
The easiest way to use Lock is with with or async with statements. The lock will be
released automatically. If rollback_on_error is enabled (default), rollbacks are automatically
handled prior to release.
Using with and async with implies blocking mode.
from postgresql_lock import Lock
# setup connection
conn = ...
# create and use lock
with Lock(conn, "shared-identifier"):
print("Acquired lock!")
# do something here
Now compare the above example to the equivalent try/finally example below:
from postgresql_lock import Lock
# setup connection
conn = ...
# create lock
lock = Lock(conn, "shared-identifier")
try:
# acquire lock
lock.acquire()
print("Acquired lock!")
try:
# do something here
pass
except Exception as exc:
# handle_error() will rollback the transaction by default
lock.handle_error(exc)
raise exc
finally:
# release lock (this is safe to run even if the lock has not been acquired)
lock.release()
Asynchronous usage (without async with)
from postgresql_lock import Lock
# setup connection
conn = ...
# create lock
lock = Lock(conn, "shared-identifier")
try:
# acquire lock
await lock.acquire_async()
print("Acquired lock!")
try:
# do something here
pass
except Exception as exc:
# handle_error_async() will rollback the transaction by default
await lock.handle_error_async(exc)
raise exc
finally:
# release lock (this is safe to run even if the lock has not been acquired)
await lock.release_async()
Non-blocking mode (supports async as well)
from postgresql_lock import Lock
# setup connection
conn = ...
# create lock
lock = Lock(conn, "shared-identifier")
# acquire lock
if lock.acquire(block=False):
# do something here
pass
else:
# could not acquire lock
pass
# release lock (this is safe to run even if the lock has not been acquired)
lock.release()
Specify the database interface manually
from postgresql_lock import Lock
# setup connection
conn = ...
# create and use lock
lock = Lock(conn, "shared-identifier", interface="asyncpg")
# do things with the lock
Handle rollbacks manually
from postgresql_lock import Lock
# setup connection
conn = ...
# create and use lock
lock = Lock(conn, "shared-identifier", rollback_on_error=False)
# do things with the lock
Changelog
- 0.2.2
- Fix: error raised when releasing transaction level locks
- 0.2.1
- Moved public Lock fields to properties
- 0.1.9
- Fix: release_async() bug for sqlalchemy connections
- 0.1.8
- Add logger() function
- Use "postgresql_lock" logger name
- 0.1.7
- Add logging statements
- 0.1.6
- Use int.from_bytes() to convert lock key into integer
- Fix: psycopg3 close() not being awaited bug
- 0.1.5
- Rename package from postgres-lock to postgresql-lock
- 0.1.4
- Add py.typed for mypy
- 0.1.3
- Key can be any object
- 0.1.2
- Add Lock.rollback_on_error (default true)
- Add Lock.handle_error() & Lock.handle_error_async()
- 0.1.1
- Key can be str or int
Metadata
Release files for postgresql-lock 0.2.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| postgresql_lock-0.2.2.tar.gz | 7.6 kB | Without provenance | Details for postgresql_lock-0.2.2.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| postgresql_lock-0.2.2-py3-none-any.whl | Python 3 | none | any | Details for postgresql_lock-0.2.2-py3-none-any.whl |
Total release size: 18.0 kB
Release files / postgresql_lock-0.2.2.tar.gz
| Download URL | postgresql_lock-0.2.2.tar.gz |
|---|---|
| Size | 7.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
48135101d3daafbc4b81c6adb8f8e448ae30d84535e0f2cfa9beb0f6f4cf911f
|
|
BLAKE2b-256 checksum How to use checksums |
b7637e05c9c85933b2a390bbb3e00b74a6fa9968f28fee8d67796d7f348d714e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.1.3 CPython/3.12.3 Linux/6.11.0-29-generic
|
Release files / postgresql_lock-0.2.2-py3-none-any.whl
| Download URL | postgresql_lock-0.2.2-py3-none-any.whl |
|---|---|
| Size | 10.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
12b3850ac76b7891d27fc5fce26cab33294b25c198a46f09cfd2588941ea433d
|
|
BLAKE2b-256 checksum How to use checksums |
69f88a8a389b328d540f06a6990c4b30fef1009337661f73aecd8e4d7d333c01
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.1.3 CPython/3.12.3 Linux/6.11.0-29-generic
|
Security for postgresql-lock 0.2.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.