benzene.kafka

Host Benzene handlers on Apache Kafka — a self-hosted consumer and a Kafka-produce outbound client. Distribution: benzene-kafka (depends only on benzene-core).

pip install benzene-kafka             # the binding + testing helpers
pip install "benzene-kafka[kafka]"    # + confluent-kafka for the real clients

Overview

Kafka is a queue/stream transport, so the binding follows the same shape as the SQS/SNS/Pub/Sub bindings (transport-bindings §"Kafka"):

The binding is duck-typed against confluent-kafka, so decode, dispatch, and send run in memory with fakes — no broker, no SDK. Only the default consumer/producer clients need the [kafka] extra.

KafkaConsumerApp — inbound

from benzene.core import application_from, build_application
from benzene.kafka import KafkaConsumerApp, run_consumer_loop

definition, _ = build_application(OrdersStartUp)
app = KafkaConsumerApp(application_from(definition))

await app.handle_message(record)          # one record -> one invocation; returns the mapped Result
await run_consumer_loop(app, consumer)    # the self-hosted worker: poll -> dispatch -> commit

KafkaMessageSender — outbound

from benzene.kafka import KafkaMessageSender

sender = KafkaMessageSender("orders-events", bootstrap_servers="localhost:9092")
await sender.send_message("orders:created", order, headers={"x-correlation-id": "abc"})

Implements the benzene.core.MessageSender port over a Kafka producer: it serializes the message to the JSON body, forwards the header dictionary onto the record's Kafka headers (so correlation/trace propagation rides across the hop), and carries the Benzene topic in the topic header. All Benzene topics are produced to the one configured Kafka topic, header-routed. A produce/flush failure (or a delivery error reported to the callback) maps to service-unavailable. Inject a producer for tests; otherwise a confluent_kafka.Producer is created lazily from bootstrap_servers.

Testing

benzene.kafka.testing provides a native-record builder and an in-memory test host, and the shared harness specializes to Kafka in one call:

from benzene.testing import create_test_host

host = create_test_host(OrdersStartUp).with_services(overrides).build_kafka()
result = await host.send_kafka("orders:place", body={"sku": "ABC", "quantity": 2})

RecordingKafkaConsumer (a replay consumer that records committed offsets) lets a test assert the loop's at-least-once behaviour without a broker. See the runnable examples/kafka_orders/.

Exports

KafkaConsumerApp, KafkaMessageSender, KafkaMessage, TOPIC_HEADER, decode_kafka_message, run_consumer_loop; and from benzene.kafka.testing: KafkaTestHost, KafkaMessageBuilder, FakeKafkaMessage, RecordingKafkaConsumer.

See also