atomic-redis-streams
atomic-streams is a small Python library that adds crash-safe, stateful processing on top of Redis Streams.
Raw Redis Streams give you persistence and at-least-once delivery but do not give:
- Atomic application state that survives crashes
- Exactly-once processing (no duplicate messages after restart)
- Downstream message publications that only happen if the callback succeeded
This library fills that gap. It wraps Redis Streams consumers in a transaction model where the callback result, application state, consumer position, and any outgoing publishes all commit together or not at all.
Installation
pip install atomic-redis-streams
Examples
The core concept is a handler: a class with a handle() method that the library calls for each message. You point a RedisStreamConsumer at a Redis stream, give it a handler, and it takes care of the rest.
Stateless consumer
The simplest handler just implements handle(). Use this when you don't need to track any state between messages:
from atomic_redis_streams import RedisStreamConsumer, TransactionManager
class Logger:
def handle(self, message: dict, transaction: TransactionManager) -> None:
print(f"Received: {message}")
consumer = RedisStreamConsumer(
stream="events",
consumer_id="logger",
handler=Logger(),
redis_url="redis://localhost:6379",
)
consumer.start()
Stateful consumer with crash recovery
Extend Persistable to persist state atomically with each message. On restart, state is restored and no message is processed twice:
from atomic_redis_streams import Persistable, PersistableAttribute, RedisStreamConsumer, TransactionManager
class OrderCounter(Persistable):
count = PersistableAttribute(default=0)
@property
def unique_id(self) -> str:
return "order-counter"
def handle(self, message: dict, transaction: TransactionManager) -> None:
self.count += 1
print(f"Processed order {message['order_id']} (total: {self.count})")
consumer = RedisStreamConsumer(
stream="orders",
consumer_id="order-processor",
handler=OrderCounter(),
redis_url="redis://localhost:6379",
)
consumer.start()
Atomic downstream publishing
Use transaction.publish() to forward messages to another stream. The publish is committed atomically with the handler, so if the handler raises, the publish is rolled back:
from atomic_redis_streams import RedisStreamConsumer, TransactionManager
class OrderRouter:
def handle(self, message: dict, transaction: TransactionManager) -> None:
transaction.publish("invoices", {"order_id": message["order_id"]})
# if an exception is raised here, the above publish() call is rolled back
consumer = RedisStreamConsumer(
stream="orders",
consumer_id="order-router",
handler=OrderRouter(),
redis_url="redis://localhost:6379",
)
consumer.start()
Full example
This example combines all three features: reading a message, updating persistent state, and publishing to a downstream stream. All three happen atomically:
from atomic_redis_streams import Persistable, PersistableAttribute, RedisStreamConsumer, TransactionManager
RESTOCK_THRESHOLD = 10
class InventoryTracker(Persistable):
stock = PersistableAttribute(default=0)
@property
def unique_id(self) -> str:
return "inventory-tracker"
def handle(self, message: dict, transaction: TransactionManager) -> None:
self.stock -= int(message["quantity"])
if self.stock <= RESTOCK_THRESHOLD:
transaction.publish("restock-alerts", {
"sku": message["sku"],
"stock": str(self.stock),
})
consumer = RedisStreamConsumer(
stream="sales",
consumer_id="inventory-tracker",
handler=InventoryTracker(),
redis_url="redis://localhost:6379",
)
consumer.start()
If the process crashes mid-flight, the stock count is not updated and the restock alert is not published. On restart, processing resumes from the last successfully committed message.
Security
This library uses pickle to serialize and deserialize Persistable handler state in Redis. It assumes a trusted Redis connection. If an attacker can write arbitrary bytes to your Redis instance, they can execute arbitrary code when the state is restored on startup. Do not use this library against an untrusted or publicly accessible Redis instance.
Metadata
Release files for atomic-redis-streams 0.1.0
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 | |
|---|---|---|---|---|
| atomic_redis_streams-0.1.0.tar.gz | 66.2 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| atomic_redis_streams-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 86.9 kB
Release files / atomic_redis_streams-0.1.0.tar.gz
| Download URL | atomic_redis_streams-0.1.0.tar.gz |
|---|---|
| Size | 66.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4e3994b5e3bbc4a7f01da5add08473e4ffc6bac3577c6b9bc2f3a01a65e6677b
|
|
BLAKE2b-256 checksum How to use checksums |
d82da3a61105c8d3d91b7f6e0ae9da025e8d956c7b516d61fd5d9dd9a1a06000
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
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 Jun 29, 2026.
Transparency logRelease files / atomic_redis_streams-0.1.0-py3-none-any.whl
| Download URL | atomic_redis_streams-0.1.0-py3-none-any.whl |
|---|---|
| Size | 20.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b9cfa8642762aba7b51eeaad7c903f94a6c7b5afc071f4f8bf24bf581641edf5
|
|
BLAKE2b-256 checksum How to use checksums |
5a083851e9405d387023f882f56e44bfbdcb85e8eade10ab5d1ecba766dadb48
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
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 Jun 29, 2026.
Transparency logSecurity for atomic-redis-streams 0.1.0
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 atomic_redis_streams-0.1.0.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 Jun 29, 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.