nats-semaphore
A distributed semaphore implementation for Python using NATS JetStream KeyValue stores. This library allows you to coordinate access to shared resources across multiple processes or services with ease.
Features
- Distributed Locking: Leverages NATS JetStream KeyValue stores for reliable distributed coordination.
- Configurable Concurrency: Define the number of slots (concurrency limit) for each semaphore.
- Asyncio Support: Built from the ground up for Python's
asyncio. - Context Manager: Easy-to-use
async withsyntax for automatic lock acquisition and release. - Timeout Handling: Support for acquisition timeouts.
- Automatic Renewal: Locks are renewed periodically while held, so the default 10 second KV TTL does not expire during longer work.
Installation
pip install nats-semaphore
Usage
Here is a simple example of how to use nats-semaphore:
import asyncio
import nats
from nats_semaphore import NatsSemaphoreContext, SemaphoreBucketConfig
async def main():
# 1. Connect to NATS
nc = await nats.connect("nats://localhost:4222")
# 2. Explicitly opt into lazy create-or-bind provisioning.
semaphore_context = NatsSemaphoreContext(nc, bucket=SemaphoreBucketConfig())
# To bind only to infrastructure provisioned elsewhere, pass its bucket name.
# This raises BucketNotFoundError on first use if the bucket does not exist.
# semaphore_context = NatsSemaphoreContext(nc, bucket="SEMAPHORES")
# 3. Define a semaphore
# 'name' identifies the resource.
# 'slot_count' is the maximum number of concurrent locks allowed.
semaphore = semaphore_context.semaphore(name="my-shared-resource", slot_count=3)
# 4. Acquire a lock using a context manager
try:
# Try to acquire a lock, waiting up to 5 seconds.
# By default, the lock is renewed every 5 seconds.
async with semaphore.lock(timeout=5.0) as lock:
print("Lock acquired! Doing work...")
await asyncio.sleep(1)
print("Work done.")
except asyncio.TimeoutError:
print("Failed to acquire lock within timeout.")
# Alternative: Manual acquire/release
try:
lock = await semaphore.acquire(timeout=5.0)
print("Manually acquired lock.")
# ... do work ...
finally:
await lock.release()
print("Manually released lock.")
# Disable automatic renewal by setting renew_interval to 0.
lock = await semaphore.acquire(timeout=5.0, renew_interval=0)
await lock.release()
await nc.close()
if __name__ == "__main__":
asyncio.run(main())
SemaphoreBucketConfig() provisions the SEMAPHORES bucket lazily with a 10 second TTL, a 1 MiB limit, memory storage, and one replica. Acquired locks are renewed every 5 seconds unless renew_interval=0 is passed to acquire() or lock().
Custom provisioning remains semaphore-specific:
from nats.js.api import StorageType
from nats_semaphore import NatsSemaphoreContext, SemaphoreBucketConfig
context = NatsSemaphoreContext(
nc,
bucket=SemaphoreBucketConfig(
bucket="MY_SEMAPHORES",
ttl=30,
max_bytes=2 * 1024 * 1024,
storage=StorageType.FILE,
replicas=3,
),
)
Migrating To 0.0.3
The context API intentionally no longer accepts kv= or native NATS KeyValueConfig values. Replace create-or-bind calls with bucket=SemaphoreBucketConfig(...). Replace kv="NAME" with bucket="NAME" only when the bucket is provisioned externally and should be bind-only.
Requirements
- Python >= 3.10
- nats-py >= 2.12
Compatibility
Compatible with nats-server versions:
- 2.7
- 2.8
- 2.9
- 2.10
- 2.11
- 2.12
- 2.14
License
Apache-2.0
Metadata
Release files for nats-semaphore 0.0.3
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 | |
|---|---|---|---|---|
| nats_semaphore-0.0.3.tar.gz | 11.7 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| nats_semaphore-0.0.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 18.0 kB
Release files / nats_semaphore-0.0.3.tar.gz
| Download URL | nats_semaphore-0.0.3.tar.gz |
|---|---|
| Size | 11.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ddddefbda4afd39d53734d4028d9883576864b1e28b98cb6cf3d41c0b5f3b44e
|
|
BLAKE2b-256 checksum How to use checksums |
ffd83d2f889fb47dc35066d525921324e87ae4de419df6959eb9018e7556fa4d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 22, 2026.
Transparency logRelease files / nats_semaphore-0.0.3-py3-none-any.whl
| Download URL | nats_semaphore-0.0.3-py3-none-any.whl |
|---|---|
| Size | 6.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
09b5cfc3b4ab29ce3db3b75b08cfd5eb0217a33ce62f55e7609a45305125c301
|
|
BLAKE2b-256 checksum How to use checksums |
63185b5139472c3bc3053204b57d409cac0aa2ade558cc1d691d50f873c390f6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 22, 2026.
Transparency logSecurity for nats-semaphore 0.0.3
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.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for nats_semaphore-0.0.3.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 22, 2026.
Transparency logA 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.