Skip to main content

Typed Python Kafka Manager - easy publish/listen to kafka topics embraced with strong types

Project description

Kavari

Easy, automated Kafka publish/subscription with strong types


This tool is to make usage of kafka super easy and safe, utilizing best practices and power given by confluent_kafka

While it may be fast & fun to use weak types in Python for rapid development, that when it comes to expose any data outside the app, it is very reasonable to structure the message in predictable manner - providing stable contract of exposed data structure for external consumers. Also, because modern applications usually are hosted in a cloud - there is a necessity to implement additional readiness for host migration/failover scenarios, when pod manager can move host from one physical place to another. That results with specific situations when:

  • kafka might not achievable temporarily
  • consumers might be taken down in the middle of processing a message(s)
  • rebalancing partitions

All of these adds a lot of code for the basic implementation for the final product.

This small library covers these, additionally providing some simplicity flavor on top.

Publishing message

Create a message type, that defines the payload (our strong 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:
        return "1"

And then publish it on the topic, just by calling:

msg: TestKafkaMessage = TestKafkaMessage("test_message")
kafka_manager.publish_message(msg, lambda msg, ex:  print("Message published"))

Easy? I hope so! Now let's consume this message

Consuming message

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

That's (almost) it! Once consumer become available via provider (any DI for example) each message is handled out of the box in separated thread, to isolate background kafka messaging processing from other part of the application (e.g. REST API)

I hope you like the concept!

To achieve full power of this lib, you need to configure it

Configuration

Install it via:

  • PIP: pip install kavari
  • Poetry: poetry add kavari

Create a kafka_manager (example below is for a DI container, but you can use it without it)

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"
        )
    )

There are 3 necessary steps to finish the configuration:

  1. Configure message consumers provider:
    Provider is a method that will deliver initialized instance of message consumer when specific key is given.
    The example manual consumer provider will look like follows:
     def consumer_provider(key: typing.Any) -> kavari.KafkaMessageConsumer:
         if key == MyFirstMessageConsumer.__class__:
             return MyFirstMessageConsumer()
    
    This interface is prepared to be compatible with dependency_injector.Container.resolve method.
  2. Start the message consumers loop when application starts.
  3. Stop the message consumers loop just before the application go down.

For instance (FastAPI + dependency_injector):

@asynccontextmanager
async def lifespan(app: FastAPI):
    # this part is called on application start
    container.logger().info("Initiating startup & background jobs")
    # consumer provider is called to get particular type of the consumer, making 
    # the autoresolve feature working out of the box
    container.kafka_manager().set_consumer_provider(container.resolve) 
    container.kafka_manager().start_consumer_loop()
    yield
    # this part is called when application is tearing down
    container.logger().info("Stopping background jobs")
    container.kafka_manager().stop_consumer_loop()

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

kavari-0.2.1.tar.gz (13.9 kB view details)

Uploaded Source

Built Distribution

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

kavari-0.2.1-py3-none-any.whl (16.6 kB view details)

Uploaded Python 3

File details

Details for the file kavari-0.2.1.tar.gz.

File metadata

  • Download URL: kavari-0.2.1.tar.gz
  • Upload date:
  • Size: 13.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.3

File hashes

Hashes for kavari-0.2.1.tar.gz
Algorithm Hash digest
SHA256 645d34e1b994ea7100cd0ef38059e52efb9f8863e94a9d53cf05860a248f7b9d
MD5 9e40120f958f98c5167fede41bb41e41
BLAKE2b-256 82fa20ccc5e08f3a9de82ba17b5b5b6aafcd4921339315cd11371cf0f751a022

See more details on using hashes here.

File details

Details for the file kavari-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: kavari-0.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

Hashes for kavari-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 210737e80a660fac566f877357cd0f5c0e117d1ab27c6909451b472d692621b5
MD5 5bbeb610de10d7b1ce1d943576641e39
BLAKE2b-256 2c19f31d8373ad5ab01871b0e5a8218a1dc1defa8e14468841b3d614142dd6b3

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page