Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/tanbro/sqlalchemy-dlock
Distributed lock based on Database and SQLAlchemy.
https://github.com/tanbro/sqlalchemy-dlock
dlock mysql orm postgres postgresql sql sqlalchemy
Last synced: 2 months ago
JSON representation
Distributed lock based on Database and SQLAlchemy.
- Host: GitHub
- URL: https://github.com/tanbro/sqlalchemy-dlock
- Owner: tanbro
- License: bsd-3-clause
- Created: 2021-01-19T11:04:53.000Z (almost 4 years ago)
- Default Branch: main
- Last Pushed: 2024-10-21T10:39:51.000Z (3 months ago)
- Last Synced: 2024-10-21T13:30:08.218Z (3 months ago)
- Topics: dlock, mysql, orm, postgres, postgresql, sql, sqlalchemy
- Language: Python
- Homepage:
- Size: 379 KB
- Stars: 13
- Watchers: 4
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
- Authors: AUTHORS.md
Awesome Lists containing this project
README
# sqlalchemy-dlock
[![Python package](https://github.com/tanbro/sqlalchemy-dlock/actions/workflows/python-package.yml/badge.svg)](https://github.com/tanbro/sqlalchemy-dlock/actions/workflows/python-package.yml)
[![PyPI](https://img.shields.io/pypi/v/sqlalchemy-dlock)](https://pypi.org/project/sqlalchemy-dlock/)
[![Documentation Status](https://readthedocs.org/projects/sqlalchemy-dlock/badge/?version=latest)](https://sqlalchemy-dlock.readthedocs.io/en/latest/)
[![codecov](https://codecov.io/gh/tanbro/sqlalchemy-dlock/branch/main/graph/badge.svg)](https://codecov.io/gh/tanbro/sqlalchemy-dlock)`sqlalchemy-dlock` is a distributed-lock library based on Database and [SQLAlchemy][].
It currently supports below locks:
Database | Lock
---------- | ---------------------------------------------------------------------------------------------
MySQL | [named lock](https://dev.mysql.com/doc/refman/en/locking-functions.html)
PostgreSQL | [advisory lock](https://www.postgresql.org/docs/current/explicit-locking.html#ADVISORY-LOCKS)## Install
```bash
pip install sqlalchemy-dlock
```## Usage
- Work with [SQLAlchemy][] [`Connection`](https://docs.sqlalchemy.org/20/core/connections.html):
```python
from sqlalchemy import create_engine
from sqlalchemy_dlock import create_sadlockkey = 'user/001'
engine = create_engine('postgresql://scott:[email protected]/')
conn = engine.connect()# Create the D-Lock on the connection
lock = create_sadlock(conn, key)# it's not lock when constructed
assert not lock.locked# lock
lock.acquire()
assert lock.locked# un-lock
lock.release()
assert not lock.locked
```- `with` statement
```python
from contextlib import closingfrom sqlalchemy import create_engine
from sqlalchemy_dlock import create_sadlockkey = 'user/001'
engine = create_engine('postgresql://scott:[email protected]/')
with engine.connect() as conn:# Create the D-Lock on the connection
with create_sadlock(conn, key) as lock:
# It's locked
assert lock.locked# Auto un-locked
assert not lock.locked# If do not want to be locked in `with`, a `closing` wrapper may help
with closing(create_sadlock(conn, key)) as lock2:
# It's NOT locked here !!!
assert not lock2.locked
# lock it now:
lock2.acquire()
assert lock2.locked# Auto un-locked
assert not lock2.locked
```- Work with [SQLAlchemy][] [`ORM` `Session`](https://docs.sqlalchemy.org/en/20/orm/session.html):
```python
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy_dlock import create_sadlockkey = 'user/001'
engine = create_engine('postgresql://scott:[email protected]/')
Session = sessionmaker(bind=engine)with Session() as session:
with create_sadlock(session, key) as lock:
assert lock.locked
assert not lock.locked
```- Asynchronous I/O Support
> đź’ˇ **TIP**
>
> - [SQLAlchemy][] `1.x`'s asynchronous I/O:
> - [SQLAlchemy][] `2.x`'s asynchronous I/O:```python
from sqlalchemy.ext.asyncio import create_async_engine
from sqlalchemy_dlock.asyncio import create_async_sadlockkey = 'user/001'
engine = create_async_engine('postgresql+asyncpg://scott:[email protected]/')
async with engine.connect() as conn:
async with create_async_sadlock(conn, key) as lock:
assert lock.locked
await lock.release()
assert not lock.locked
await lock.acquire()
assert not lock.locked
```> ℹ️ **NOTE** \
> [aiomysql][], [asyncpg][] and [psycopg][] are tested asynchronous drivers.
>
> We can install it with asynchronous DB libraries:
>
> ```bash
> pip install SQLAlchemy[asyncio] aiomysql sqlalchemy-dlock
> ```
>
> or
>
> ```bash
> pip install SQLAlchemy[asyncio] asyncpg sqlalchemy-dlock
> ```## Test
Following drivers are tested:
- MySQL:
- [mysqlclient][] (synchronous)
- [pymysql][] (synchronous)
- [aiomysql][] (asynchronous)
- Postgres:
- [psycopg2][] (synchronous)
- [asyncpg][] (asynchronous)
- [psycopg][] (synchronous and asynchronous)You can run unit-tests
- on local environment:
1. Install the project in editable mode with `asyncio` optional dependencies, and libraries/drivers needed in test. A virtual environment ([venv][]) is strongly advised:
```bash
pip install -e .[asyncio] -r tests/requirements.txt
```1. start up mysql and postgresql service
There is a docker [compose][] file `db.docker-compose.yml` in project's top directory,
which can be used to run mysql and postgresql develop environment conveniently:```bash
docker compose -f db.docker-compose.yml up
```1. set environment variables `TEST_URLS` and `TEST_ASYNC_URLS` for sync and async database connection url.
Multiple connections separated by space.eg: (following values are also the defaults, and can be omitted)
```ini
TEST_URLS=mysql://test:[email protected]/test postgresql://postgres:[email protected]/
TEST_ASYNC_URLS=mysql+aiomysql://test:[email protected]/test postgresql+asyncpg://postgres:[email protected]/
```> ℹ️ **NOTE** \
> The test cases would load environment variables from dot-env file `tests/.env`.1. run unit-test
```bash
python -m unittest
```- or on docker [compose][]:
`tests/docker-compose.yml` defines a Python and [SQLAlchemy][] version matrix -- it combines Python `3.8` to `3.12` and [SQLAlchemy][] `v1`/`v2` for test cases. We can run it by:
```bash
cd tests
docker compose up --abort-on-container-exit
```[SQLAlchemy]: https://www.sqlalchemy.org/ "The Python SQL Toolkit and Object Relational Mapper"
[venv]: https://docs.python.org/library/venv.html "The venv module supports creating lightweight “virtual environments”, each with their own independent set of Python packages installed in their site directories. "
[mysqlclient]: https://pypi.org/project/mysqlclient/ "Python interface to MySQL"
[psycopg2]: https://pypi.org/project/psycopg2/ "PostgreSQL database adapter for Python"
[psycopg]: https://pypi.org/project/psycopg/ "Psycopg 3 is a modern implementation of a PostgreSQL adapter for Python."
[aiomysql]: https://pypi.org/project/aiomysql/ "aiomysql is a “driver” for accessing a MySQL database from the asyncio (PEP-3156/tulip) framework."
[asyncpg]: https://pypi.org/project/asyncpg/ "asyncpg is a database interface library designed specifically for PostgreSQL and Python/asyncio. "
[pymysql]: https://pypi.org/project/pymysql/ "Pure Python MySQL Driver"
[compose]: https://docs.docker.com/compose/ "Compose is a tool for defining and running multi-container Docker applications."