Skip to main content

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, unlock and 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 the logging module under the lockingcenter.mutex logger). 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 global socket.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

lockingcenter-1.0.0.tar.gz (16.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

lockingcenter-1.0.0-py3-none-any.whl (13.0 kB view details)

Uploaded Python 3

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

Hashes for lockingcenter-1.0.0.tar.gz
Algorithm Hash digest
SHA256 470a7c24be4512aa34769417f6d7fbaf905e7d2c816b3296664d4a2edf30ef22
MD5 2ddccf0f3fcee9d0b01bd6d9cfbbf19f
BLAKE2b-256 64f757a1e3950de59b35e455abc2a4fc2aa28f7b16629887d3032e4132a2df6e

See more details on using hashes here.

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

Hashes for lockingcenter-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1ca0376bb7f92e4b2c30942fee462649052b1759c6882062c9e80198d334b589
MD5 d8c7be0fb5fce38cd3330c322ed558d5
BLAKE2b-256 571c37e8fa38571606b680a86d0abb15e4023733ed8e083524a17276b2156f3a

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page