Typed Python Kafka Manager - easy publish/listen to kafka topics embraced with strong types
Project description
Kavari
Easy, automated Kafka publish/subscribe with strong typing
This tool aims to make Kafka usage extremely simple and safe,
leveraging best practices and the power of confluent_kafka.
While using weak typing in Python may be quick and fun for rapid development, exposing any data outside your app requires a predictable and structured format. Providing a stable contract for external consumers ensures maintainability and safety.
Additionally, since modern applications are usually hosted in the cloud, there’s often a need to handle scenarios like host migration or failover. For instance:
- Kafka may become temporarily unavailable
- Consumers may shut down in the middle of message processing
- Partition rebalancing may occur
These situations typically require a lot of extra code in a production-ready setup.
This small library handles those concerns for you — while also simplifying the developer experience.
📨 Publishing messages
Create a message type that defines the payload (our strongly typed message format):
class TestKafkaMessage(KafkaMessage):
topic = "test_topic"
def __init__(self, payload: str):
super().__init__()
self.payload: str = payload
def get_partition_key(self) -> str:
"""
The message key in the produce method is important for determining how messages are
distributed across partitions in a Kafka topic. By using a key, all messages with the same
key will go to the same partition and kafka will ensure the order of them. Think about it in
terms of aggregate ID
:return: str
"""
return "1"
Then publish it to the topic simply by calling:
msg = TestKafkaMessage("test_message")
kafka_manager.publish_message(msg, lambda msg, ex: print("Message published"))
📥 Consuming messages
Define the handler class:
@kafka_message_handler(message_cls=TestKafkaMessage)
class TestKafkaMessageConsumer(KafkaMessageConsumer):
def __init__(self):
self.received_message: str | None = None
def handle(self, message_data: str) -> None:
self.received_message = message_data
Once the consumer is available via a provider (e.g. a DI container), each message will be handled in a separate thread,
which keeps Kafka background processing isolated from other parts of your app (e.g. REST API).
⚙️ Configuration
Install using:
- pip:
pip install kavari - Poetry:
poetry add kavari
Create a kafka_manager (example below uses a DI container, but Kavari works without one as well):
from kavari import kavari_create, FibonacciRetryPolicy, KafkaManager
class Container(DeclarativeContainer):
kafka_manager: Singleton[KafkaManager] = Singleton(
lambda: kavari_create(
bootstrap_servers="bootstrap_location:2973",
group_id="unique_group_identifier",
publishing_retry_policy=FibonacciRetryPolicy(max_attempts=10),
logger=logger,
auto_commit=False,
auto_offset_reset="earliest"
)
)
✅ Configuration steps
- Configure the message consumer provider:
def consumer_provider(key: typing.Any) -> kavari.KafkaMessageConsumer:
if key == MyFirstMessageConsumer.__class__:
return MyFirstMessageConsumer()
- Start the consumer loop at application startup.
- Stop the consumer loop during application shutdown.
Example (FastAPI + Dependency Injector)
@asynccontextmanager
async def lifespan(app: FastAPI):
container.logger().info("Starting background jobs...")
container.kafka_manager().set_consumer_provider(container.resolve)
container.kafka_manager().start_consumer_loop()
yield
container.logger().info("Stopping background jobs...")
container.kafka_manager().stop_consumer_loop()
🔍 Want to contribute?
Contributions, issues and feature requests are welcome!
Feel free to check issues page.
If you love this project, leave a ⭐ on GitHub!
📃 License
This project is licensed under the Apache 2.0 License.
Project details
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 kavari-0.2.2.1.tar.gz.
File metadata
- Download URL: kavari-0.2.2.1.tar.gz
- Upload date:
- Size: 13.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f42a384992bb09221bd73f3f36ea00f2a02d46c30c5a1fa08a10395d48ce9fe4
|
|
| MD5 |
df796fd2df48daa7237ea7f3b8be0c4e
|
|
| BLAKE2b-256 |
2f5afbb6bfe76f5193edd2744af369f9761cdee167685c02b14353f24d0fc046
|
File details
Details for the file kavari-0.2.2.1-py3-none-any.whl.
File metadata
- Download URL: kavari-0.2.2.1-py3-none-any.whl
- Upload date:
- Size: 16.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0dbce0e56458429323b78ef3aa18a2c8610f51b362247e93dc80e8b70e00d431
|
|
| MD5 |
e7180e54451a51da7b8d467f3350780f
|
|
| BLAKE2b-256 |
d1e92a1b2fb14898e1e37605563e2a241c482e886766e26748b976abf77af3e0
|