Eventbase
Couriers that publish and poll events. An event is binary content with json metadata. It travels on a bus (a kafka topic or a watched directory), and its content can be claim checked into a store (an s3 bucket or a directory) so only a small json claim crosses the bus.
pip install eventbase # directory only, standard library
pip install "eventbase[kafka]" # + kafka bus (aiokafka)
pip install "eventbase[s3]" # + s3 store (aiobotocore)
pip install "eventbase[all]"
Couriers
| Mode | Construct | Metadata lives in |
|---|---|---|
| Directory only (default) | Courier.directory(path, prefixes=()) |
filesystem stat |
| Kafka only | Courier.kafka(topic) |
kafka headers |
| Kafka + S3 claim check | Courier.kafka(topic, store=S3Store(bucket)) |
s3 user metadata |
| Kafka + directory claim check | Courier.kafka(topic, store=DirectoryStore(path)) |
kafka headers + stat |
import asyncio
from eventbase import Courier, S3Store
async def main():
store = S3Store("events", prefix="inbox", endpoint="http://localhost:9000")
async with Courier.kafka("events", store=store, bootstrap="localhost:9092", parallel=16) as courier:
assert await courier.ping(timeout=5)
await courier.publish(b"\x89PNG...", {"source": "camera", "frame": 12})
for message in await courier.poll(limit=50):
print(message.id, len(message.content), message.metadata)
await courier.acknowledge(message)
asyncio.run(main())
API
connect()/disconnect(), orasync with.ping(timeout=5.0) -> bool- bus and store both answer in time.publish(content, metadata=None, key=None) -> str- returns the key.poll(limit=10, sequential=False, timeout=1.0) -> list[Message]- claimed content is fetched concurrently, at mostparallelat a time (set on the courier), or one by one withsequential=True. Order is preserved.acknowledge(message)- kafka commits the offset; the directory bus moves the file into.done/. Stores are never touched.release(messages)- hand polled, unacknowledged messages back so the next poll redelivers them (kafka seeks back; the directory bus forgets them).
Runner
A run-forever loop over a courier. handle may be async def or a plain
function (run on a worker thread).
from eventbase import Courier, Runner
async def handle(message):
... # raise to retry
runner = Runner(
Courier.directory("/inbox", prefixes=["invoice_"]),
handle,
retries=3, # then give up on the message
dead=Courier.directory("/dead"), # where given-up messages go
concurrency=1, # >1 handles a batch concurrently
)
await runner.run() # until runner.stop(), SIGINT or SIGTERM
- At least once: a message is acknowledged only after
handlereturns, in bus order, never past a failure. A failure releases the rest of the batch and retries afterpause. - After
retriesfailures the message is published todead(metadata gainserrorandfailures), or dropped and logged when there is nodead, then acknowledged. - Broker, store or dead-letter errors disconnect and reconnect with a doubling
backoff from
pauseup toceiling. - Stopping finishes the batch in hand before returning.
Behaviour notes
- Metadata is encoded one key per kafka header /
x-amz-meta-*entry, each value json. S3 lowercases keys and caps metadata at 2KB per object. - Files cannot hold metadata, so directory messages carry
key,name,size,modifiedandtypefrom the filesystem. With kafka in front, published metadata rides the headers and merges over those. - The directory bus picks up any visible file, oldest first, recursively;
prefixesrestricts it to paths starting with one of them. Hidden names (in-flight.tmpwrites,.done/) are skipped. Polled but unacknowledged files are not handed out twice until the courier reconnects. - Kafka commits a position: acknowledging a record acknowledges every earlier record of its partition. The consumer joins its group on the first poll, so publish-only couriers never join one.
Tests
pytest --cov # unit tests with coverage
docker run -d -p 9092:9092 apache/kafka:latest
moto_server -p 9000 & # s3, from the dev extra
EVENTBASE_KAFKA=localhost:9092 EVENTBASE_S3=http://localhost:9000 \
AWS_ACCESS_KEY_ID=test AWS_SECRET_ACCESS_KEY=test pytest tests/test_live.py
Metadata
Release files for eventbase 1.0.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 | |
|---|---|---|---|
| eventbase-1.0.0.tar.gz | 18.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| eventbase-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 36.8 kB
Release files / eventbase-1.0.0.tar.gz
| Download URL | eventbase-1.0.0.tar.gz |
|---|---|
| Size | 18.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5603a99b2ce5d622da745bcb7d0fa2eebfed08c21c614fa42d6b750860998bff
|
|
BLAKE2b-256 checksum How to use checksums |
733aa8c954984bff12e05140a8bdbe835ce3e0edd9e1828e4d8c6c1530857e50
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.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 Oct 13, 2026.
Transparency logRelease files / eventbase-1.0.0-py3-none-any.whl
| Download URL | eventbase-1.0.0-py3-none-any.whl |
|---|---|
| Size | 18.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6631a73c511616c59ec13538d3c354ebd87434813c848d44d6f6e6b716675f02
|
|
BLAKE2b-256 checksum How to use checksums |
8d9513f4cc0dda97643d8d3f92fcf364c569277eb4b20a2eeaba297ede5c57d8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.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 Oct 13, 2026.
Transparency log