Locking-Center Python Client
The Python connector for Locking-Center, a mutex point that synchronizes access to shared resources between different services. Lock a key before you touch the resource, do the work, unlock the key. Only one caller holds a given key at a time, the rest queue up and are served in order.
Python 3.10 or newer, standard library only (no dependencies).
Installation
pip install ./clients/python # from a checkout of the repository
Quick start
from lockingcenter import LockingCenter
m = LockingCenter("localhost:22119")
m.lock("locking-key")
try:
print("Hello from the locked area!")
finally:
m.unlock("locking-key")
Connecting
# simplest form
m = LockingCenter("localhost:22119")
# with a source address, which identifies this owner for crash recovery, see below
m = LockingCenter("localhost:22119", source="10.0.0.4")
The constructor dials the server once to make sure it is reachable and raises ConnectionError if it is not. A
malformed address or a source longer than 127 bytes raises ValueError. The returned object is safe to keep and share
across threads; every call opens its own short-lived connection.
API
| Method | Blocks | Description |
|---|---|---|
lock(key) |
yes | Acquires the key, waiting in the queue until it is free |
try_lock(key) -> bool |
no | Acquires the key only if it is free right now, returns whether it did |
unlock(key) |
no | Releases the key |
wait(key) |
yes | Waits for the key to be free, then releases it again without holding it |
reset_by_key(key) |
no | Force releases a key, whoever holds it (crash recovery) |
reset_by_source(source) |
no | Force releases everything a given owner held (crash recovery) |
Locking
lock blocks until the key is free, then takes it. It keeps trying through connection failures, so it returns only
once the key is held.
m.lock("orders/batch-7")
try:
... # exclusive work
finally:
m.unlock("orders/batch-7")
Try locking
try_lock is the non-blocking form. It takes the key only if it is free at that moment and returns immediately, so you
decide what to do when somebody else holds it.
if m.try_lock("orders/batch-7"):
try:
... # exclusive work
finally:
m.unlock("orders/batch-7")
else:
... # someone else holds it, skip, retry later, or do something else
try_lock returns False when the key is held by another owner and when the server cannot be reached, so a
False means only "you did not get the lock". If you need to tell the two apart, check reachability separately.
Waiting
wait blocks until the key is free and then releases it immediately, without holding it. Use it to pause until whoever
holds the key is done.
m.wait("migration-done") # returns once the key is free
Crash recovery: reset
A lock is not tied to its TCP connection, so a client that crashes while holding a key leaves that key locked. Nothing releases it automatically. Reset is how an operator or a supervisor clears such a stuck lock.
m.reset_by_key("orders/batch-7") # release this key, whoever holds it
m.reset_by_source("10.0.0.9") # release everything 10.0.0.9 held
reset_by_source matches on the source address. Pass the source when you construct the client
(LockingCenter(address, source=...)) so that each owner is identifiable; on Kubernetes, pass the pod IP. A None
source lets the server fall back to the connection's peer address.
Keys
A key must be between 1 and 127 bytes. Keys are sent UTF-8 encoded and the limit is on the encoded size, so a
non-ASCII key such as "café-ключ" (9 characters, 14 bytes) counts as 14. An empty or over-long key is a programming
error, so the client raises ValueError right away, before touching the network, instead of hanging in the retry loop.
Keep keys within that range, they are arbitrary text otherwise.
Behaviour to know
lock,unlockand the resets keep retrying until they succeed. They do not raise; a server that is down just means the call keeps trying (with a 500 ms delay between attempts, logged as a warning through theloggingmodule under thelockingcenter.mutexlogger). Run a call in your own thread with a timeout if you need to give up.- There is no read timeout on the connection for
lock. The server holds the connection open for as long as the key is held by its current owner, which is unbounded. The client already accounts for this and ignores any globalsocket.setdefaulttimeout(). - Every call is one short-lived TCP connection. There is no pool to manage and nothing to close.
- The client is safe for concurrent use from many threads.
Development
cd clients/python
python3 -m unittest discover -s tests -v
tests/test_encoding.py checks the exact bytes of every request and needs no server. tests/test_integration.py
starts a real server binary for every test; point LOCKD_SERVER at the binary and, if needed, LOCKD_PORT at a free
port (the server also takes the two ports after it). The integration tests are skipped when the binary is not found.
Getting a server for the tests
The integration tests start a real server themselves. Build it from the
server repository and point LOCKD_SERVER at it;
go build -o lockd-server ./mutex
LOCKD_SERVER=/path/to/lockd-server python3 -m unittest discover -s tests -v
Without LOCKD_SERVER the integration tests are skipped with a message; the encoding tests always run. LOCKD_PORT
(default 29300) picks the port the test server binds; it also takes the two ports above it.
License
Apache License 2.0. The Locking-Center server itself is licensed separately under the GPL-3.0; the clients are permissive so they can be embedded in any service.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file lockingcenter-1.0.0.tar.gz.
File metadata
- Download URL: lockingcenter-1.0.0.tar.gz
- Upload date:
- Size: 16.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.10.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
470a7c24be4512aa34769417f6d7fbaf905e7d2c816b3296664d4a2edf30ef22
|
|
| MD5 |
2ddccf0f3fcee9d0b01bd6d9cfbbf19f
|
|
| BLAKE2b-256 |
64f757a1e3950de59b35e455abc2a4fc2aa28f7b16629887d3032e4132a2df6e
|
File details
Details for the file lockingcenter-1.0.0-py3-none-any.whl.
File metadata
- Download URL: lockingcenter-1.0.0-py3-none-any.whl
- Upload date:
- Size: 13.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.10.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1ca0376bb7f92e4b2c30942fee462649052b1759c6882062c9e80198d334b589
|
|
| MD5 |
d8c7be0fb5fce38cd3330c322ed558d5
|
|
| BLAKE2b-256 |
571c37e8fa38571606b680a86d0abb15e4023733ed8e083524a17276b2156f3a
|