--- title: "Apache Kafka transport" description: "The babelqueue-kafka transport — a canonical-envelope publisher and a URN-routed, process-then-commit consumer over kafka-clients, on the framework-agnostic core." source: https://babelqueue.com/docs/babelqueue-java/1.x/apache-kafka/ updated: 2026-06-14T00:00:00.000Z --- # Apache Kafka transport `com.babelqueue:babelqueue-kafka` is an Apache Kafka transport on the Java core. It sends the [canonical envelope](/docs/spec/1.x/envelope/) as the record value with the [§6 header projection](/docs/spec/1.x/broker-bindings/#apache-kafka), and consumes by routing each record to a handler by URN — so a record it produces is consumed by any other BabelQueue SDK, and vice-versa. Kafka has no native ack/delay/DLQ/delivery-counter, so the binding absorbs all four in the transport. ## Install Maven: ```xml com.babelqueue babelqueue-kafka 1.0.0 ``` Requirements: **Java 17+**. It pulls `babelqueue-core` and `org.apache.kafka:kafka-clients` transitively. You supply the Kafka `Producer` / `Consumer`. ## Produce ```java import com.babelqueue.kafka.KafkaPublisher; import org.apache.kafka.clients.producer.*; import org.apache.kafka.common.serialization.ByteArraySerializer; import java.util.Map; Map cfg = Map.of( ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092", ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, ByteArraySerializer.class, ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, ByteArraySerializer.class); try (Producer producer = new KafkaProducer<>(cfg)) { String id = KafkaPublisher.create(producer, "orders") .publish("urn:babel:orders:created", Map.of("order_id", 1042L)); } ``` `publish(urn, data)` returns the message `meta.id`; overloads add a `traceId` and a relative `Duration delay` (delays require a `RetryTopics` topology, else they raise). ## Consume ```java import com.babelqueue.kafka.*; import org.apache.kafka.clients.consumer.*; import org.apache.kafka.common.serialization.ByteArrayDeserializer; import java.time.Duration; import java.util.List; Consumer consumer = new KafkaConsumer<>(Map.of( ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092", ConsumerConfig.GROUP_ID_CONFIG, "orders-workers", ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false, // manual commit (process-then-commit) ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, ByteArrayDeserializer.class, ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, ByteArrayDeserializer.class)); consumer.subscribe(List.of("orders")); RetryTopics retry = RetryTopics.forTopic("orders") .tier(Duration.ofSeconds(5)).tier(Duration.ofMinutes(1)).build(); com.babelqueue.kafka.KafkaConsumer worker = com.babelqueue.kafka.KafkaConsumer.builder(consumer) .producer(producer) .retryTopics(retry) .maxTries(3) .handler("urn:babel:orders:created", (envelope, record) -> { // envelope.data(), envelope.traceId(), envelope.attempts() ... }) .build(); worker.run(() -> true); // poll → process → commit ``` A throwing handler republishes the envelope to the next `.retry.` tier with `bq-attempts + 1`, then commits; once `maxTries` is reached it goes to `.dlq` with a `dead_letter` block. The consumer routes on the `bq-job` header. Unknown-URN strategy is one of `fail` / `delete` / `release` / `dead_letter`. ## Contract mapping (§6) | Envelope | Apache Kafka | | :--- | :--- | | body | record `value` (byte-identical across SDKs) | | `job` (URN) | header `bq-job` (consumer routes on this) | | `trace_id` | header `bq-trace-id` | | `meta.id` | header `bq-message-id` | | `meta.schema_version` | header `bq-schema-version` | | `meta.lang` | header `bq-source-lang` | | `meta.created_at` | record `timestamp` (Unix ms) | | `attempts` | header `bq-attempts` (**authoritative**; body is the fallback) | | reserve / ack | poll → process → **commit offset** (manual) | | retry / delay | republish to `.retry.` (`bq-attempts + 1`) | | dead-letter | `.dlq` + `dead_letter` block | The Kafka `Consumer` is mocked with Mockito and the producer with the official `MockProducer` — no Kafka, no network. The envelope is unchanged (`schema_version` stays `1`); Apache Kafka is purely additive.