postgresql-lock


Namepostgresql-lock JSON
Version 0.2.2 PyPI version JSON
download
home_pagehttps://github.com/seankerr/py-postgresql-lock
SummaryLock mechanism implemented with PostgreSQL advisory locks.
upload_time2025-07-11 19:11:13
maintainerNone
docs_urlNone
authorSean Kerr
requires_python<4.0,>=3.7
licenseBSD-3-Clause
keywords postgresql postgres distributed lock
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage
            ## postgresql-lock

Lock mechanism implemented with PostgreSQL advisory locks.

Easily implement distributed database locking.

### Install

```sh
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 `INSERT` and `UPDATE` on 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._

```python
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:

```python
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`)

```python
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)

```python
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

```python
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

```python
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

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/seankerr/py-postgresql-lock",
    "name": "postgresql-lock",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4.0,>=3.7",
    "maintainer_email": null,
    "keywords": "postgresql, postgres, distributed, lock",
    "author": "Sean Kerr",
    "author_email": "sean@code-box.org",
    "download_url": "https://files.pythonhosted.org/packages/b7/63/7e05c9c85933b2a390bbb3e00b74a6fa9968f28fee8d67796d7f348d714e/postgresql_lock-0.2.2.tar.gz",
    "platform": null,
    "description": "## postgresql-lock\n\nLock mechanism implemented with PostgreSQL advisory locks.\n\nEasily implement distributed database locking.\n\n### Install\n\n```sh\npip install postgresql-lock\n```\n\n### Supported database interfaces\n\n-   **asyncpg**\n    -   asynchronous\n-   **psycopg2**\n    -   synchronous\n-   **psycopg3**\n    -   asynchronous\n    -   synchronous\n-   **sqlalchemy** (supports version 1 & 2; can use any underlying database interface)\n    -   asynchronous\n    -   synchronous\n\n### Why would I use this?\n\n-   PostgreSQL table locks aren't sufficient for your use-case\n-   PostgreSQL row locks don't work on `INSERT`\n-   You want to prevent race conditions between `INSERT` and `UPDATE` on the same primary key\n-   None of the aforementioned details fit your use-case, but you have PostgreSQL installed and need to prevent race conditions in a distributed system\n\n### Default operation\n\nBy default `postgresql-lock` will use `session` lock scope in `blocking` mode with\n`rollback_on_error` enabled. The `session` lock scope means only a single database connection can\nacquire the lock at a time.\n\n### Usage\n\nAll work revolves around the `Lock` class.\n\nThe easiest way to use `Lock` is with `with` or `async with` statements. The lock will be\nreleased automatically. If `rollback_on_error` is enabled (default), rollbacks are automatically\nhandled prior to release.\n\n_Using `with` and `async with` implies blocking mode._\n\n```python\nfrom postgresql_lock import Lock\n\n# setup connection\nconn = ...\n\n# create and use lock\nwith Lock(conn, \"shared-identifier\"):\n    print(\"Acquired lock!\")\n\n    # do something here\n```\n\nNow compare the above example to the equivalent try/finally example below:\n\n```python\nfrom postgresql_lock import Lock\n\n# setup connection\nconn = ...\n\n# create lock\nlock = Lock(conn, \"shared-identifier\")\n\ntry:\n    # acquire lock\n    lock.acquire()\n\n    print(\"Acquired lock!\")\n\n    try:\n        # do something here\n        pass\n\n    except Exception as exc:\n        # handle_error() will rollback the transaction by default\n        lock.handle_error(exc)\n\n        raise exc\nfinally:\n    # release lock (this is safe to run even if the lock has not been acquired)\n    lock.release()\n```\n\n### Asynchronous usage (without `async with`)\n\n```python\nfrom postgresql_lock import Lock\n\n# setup connection\nconn = ...\n\n# create lock\nlock = Lock(conn, \"shared-identifier\")\n\ntry:\n    # acquire lock\n    await lock.acquire_async()\n\n    print(\"Acquired lock!\")\n\n    try:\n        # do something here\n        pass\n\n    except Exception as exc:\n        # handle_error_async() will rollback the transaction by default\n        await lock.handle_error_async(exc)\n\n        raise exc\nfinally:\n    # release lock (this is safe to run even if the lock has not been acquired)\n    await lock.release_async()\n```\n\n### Non-blocking mode (supports async as well)\n\n```python\nfrom postgresql_lock import Lock\n\n# setup connection\nconn = ...\n\n# create lock\nlock = Lock(conn, \"shared-identifier\")\n\n# acquire lock\nif lock.acquire(block=False):\n    # do something here\n    pass\n\nelse:\n    # could not acquire lock\n    pass\n\n# release lock (this is safe to run even if the lock has not been acquired)\nlock.release()\n```\n\n### Specify the database interface manually\n\n```python\nfrom postgresql_lock import Lock\n\n# setup connection\nconn = ...\n\n# create and use lock\nlock = Lock(conn, \"shared-identifier\", interface=\"asyncpg\")\n\n# do things with the lock\n```\n\n### Handle rollbacks manually\n\n```python\nfrom postgresql_lock import Lock\n\n# setup connection\nconn = ...\n\n# create and use lock\nlock = Lock(conn, \"shared-identifier\", rollback_on_error=False)\n\n# do things with the lock\n```\n\n### Changelog\n\n-   **0.2.2**\n    -   Fix: error raised when releasing transaction level locks\n-   **0.2.1**\n    -   Moved public Lock fields to properties\n-   **0.1.9**\n    -   Fix: release_async() bug for sqlalchemy connections\n-   **0.1.8**\n    -   Add logger() function\n    -   Use \"postgresql_lock\" logger name\n-   **0.1.7**\n    -   Add logging statements\n-   **0.1.6**\n    -   Use int.from_bytes() to convert lock key into integer\n    -   Fix: psycopg3 close() not being awaited bug\n-   **0.1.5**\n    -   Rename package from postgres-lock to postgresql-lock\n-   **0.1.4**\n    -   Add py.typed for mypy\n-   **0.1.3**\n    -   Key can be any object\n-   **0.1.2**\n    -   Add Lock.rollback_on_error (default true)\n    -   Add Lock.handle_error() & Lock.handle_error_async()\n-   **0.1.1**\n    -   Key can be str or int\n",
    "bugtrack_url": null,
    "license": "BSD-3-Clause",
    "summary": "Lock mechanism implemented with PostgreSQL advisory locks.",
    "version": "0.2.2",
    "project_urls": {
        "Homepage": "https://github.com/seankerr/py-postgresql-lock",
        "Repository": "https://github.com/seankerr/py-postgresql-lock"
    },
    "split_keywords": [
        "postgresql",
        " postgres",
        " distributed",
        " lock"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "69f88a8a389b328d540f06a6990c4b30fef1009337661f73aecd8e4d7d333c01",
                "md5": "eb671d60907503637f4d28b094b43440",
                "sha256": "12b3850ac76b7891d27fc5fce26cab33294b25c198a46f09cfd2588941ea433d"
            },
            "downloads": -1,
            "filename": "postgresql_lock-0.2.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "eb671d60907503637f4d28b094b43440",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0,>=3.7",
            "size": 10379,
            "upload_time": "2025-07-11T19:11:12",
            "upload_time_iso_8601": "2025-07-11T19:11:12.488814Z",
            "url": "https://files.pythonhosted.org/packages/69/f8/8a8a389b328d540f06a6990c4b30fef1009337661f73aecd8e4d7d333c01/postgresql_lock-0.2.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "b7637e05c9c85933b2a390bbb3e00b74a6fa9968f28fee8d67796d7f348d714e",
                "md5": "ef153ce3711ed2ba5b7f7ae5640e2864",
                "sha256": "48135101d3daafbc4b81c6adb8f8e448ae30d84535e0f2cfa9beb0f6f4cf911f"
            },
            "downloads": -1,
            "filename": "postgresql_lock-0.2.2.tar.gz",
            "has_sig": false,
            "md5_digest": "ef153ce3711ed2ba5b7f7ae5640e2864",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0,>=3.7",
            "size": 7628,
            "upload_time": "2025-07-11T19:11:13",
            "upload_time_iso_8601": "2025-07-11T19:11:13.737271Z",
            "url": "https://files.pythonhosted.org/packages/b7/63/7e05c9c85933b2a390bbb3e00b74a6fa9968f28fee8d67796d7f348d714e/postgresql_lock-0.2.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-07-11 19:11:13",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "seankerr",
    "github_project": "py-postgresql-lock",
    "travis_ci": false,
    "coveralls": true,
    "github_actions": false,
    "lcname": "postgresql-lock"
}
        
Elapsed time: 0.43106s