Kafka Channel Adapter
The kafka-channel-adapter module provides integration with Apache Kafka 3.6.x.
Dependency
<dependency>
<groupId>io.pipelite</groupId>
<artifactId>kafka-channel-adapter</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
Usage as source (consumer)
Pipelite.defineFlow("kafka-consumer")
.fromSource("kafka://my-topic")
.process("handle", (exchange, contribution) -> {
String record = exchange.getInputPayloadAs(String.class);
// process the Kafka record
})
.toSink("slf4j://log")
.build();
The Kafka source runs its own poll loop against the Kafka client on a dedicated thread, then hands each record to the framework, which makes it durable and queues it before the offsets are committed, as it does for every event source. The consumer is closed by that same thread when the flow stops.
The same settings can be applied through the typed KafkaSourceConfigurer instead of a query
string (see Custom Channel Adapters for the general mechanism):
.fromSource("kafka://my-topic", (KafkaSourceConfigurer c) -> c
.groupId("my-consumer-group")
.autoOffsetReset("earliest"))
Headers of the record
The record key is always put on the exchange, in the header org.apache.kafka.record_key. The other headers of the record do not reach the flow unless the flow asks for them, see Headers from and to the outside. Besides the headers of the record, these are offered with the names below:
| Name | Value |
|---|---|
|
The topic the record was read from. |
|
The partition. |
|
The offset of the record in its partition. |
|
The timestamp of the record, in milliseconds since the epoch. |
.fromSource("kafka://orders", (KafkaSourceConfigurer c) -> c
.propagateHeaders(h -> h.filter("Idempotency-Key", "Kafka-Offset")))
The headers of a Kafka record are bytes: they are read as UTF-8 text. When a name is repeated the last value is kept, and a header with no value is left out.
URL format
kafka://<topic-name>[?group.id=<id>&auto.offset.reset=<policy>]
The query-string keys are Kafka’s own native ConsumerConfig property names (group.id, auto.offset.reset) - the KafkaSourceConfigurer methods above are camelCase Java, but lower into these same native keys underneath, so the source reads one consistent shape regardless of which style built the URL.
|
Usage as sink (producer)
.toSink("kafka://output-topic")
The DefaultKafkaProducer sends the serialized payload as the Kafka record value, and the header org.apache.kafka.record_key, if the exchange has it, as the record key.
The headers of the exchange are not sent unless the flow chooses them:
.toSink("kafka://output-topic", (KafkaSinkConfigurer c) -> c
.propagateHeaders(h -> h.filter("Idempotency-Key", "X-Tenant-Id")))
They become the headers of the record, written as UTF-8 text. See Headers from and to the outside.
Configuration
Kafka configuration is provided via KafkaChannelConfigurer, registered on the context:
context.addChannelConfigurer((KafkaChannelConfigurer) config -> {
config.setBootstrapServers("localhost:9092");
config.setGroupId("pipelite-consumer-group");
config.setAutoOffsetReset("earliest");
});
With Spring Boot, register it from a bean implementing PipeliteContextInitializer instead - see
Configuration Properties. A plain @Bean
returning a KafkaChannelConfigurer is not picked up automatically.