Historical Note: This was originally written in early 2022, there may be better ways now.
This post demonstrates how to send Kafka events to dynamic topics in Red Hat Quarkus 2.
I previously used the KafkaProducer, but the metadata was ignored resulting in serialization issues.
The solution was to use a standard emitter and to attach the topic metadata directly to the outgoing message.
@ApplicationScoped
public class RoutingReflector implements Reflector {
private static final Logger logger = Logger.getLogger(RouteTable.class);
@Inject
@Channel("reflector")
Emitter<EventEnvelope> emitter;
private final RouteTable routeTable;
private final String defaultTopic;
public RoutingReflector(RouteTable routeTable) {
this.routeTable = routeTable;
var configProvider = ConfigProvider.getConfig();
defaultTopic = configProvider.getValue("defaultTopic", String.class);
logger.info("default topic: " + defaultTopic);
}
@Override
public void reflect(Message<JsonObject> message, EventEnvelope event) {
var topics = routeTable.getTopics(event);
if (topics.isEmpty()) {
emit(defaultTopic, event);
return;
}
for (var topic: topics) {
emit(topic, event);
}
}
private void emit(String topic, EventEnvelope event) {
OutgoingKafkaRecordMetadata<?> metadata = OutgoingKafkaRecordMetadata.builder()
.withTopic(topic)
.build();
emitter.send(Message.of(event).addMetadata(metadata));
}
}
The reflector channel is initialized in the application.properties resource:
mp.messaging.outgoing.reflector.cloud-events-source
= reflectorservice
mp.messaging.outgoing.reflector.connector
= smallrye-kafka
mp.messaging.outgoing.reflector.value.serializer
= org.apache.kafka.common.serialization.StringSerializer
mp.messaging.outgoing.reflector.cloud-events-mode
= structured
mp.messaging.outgoing.reflector.cloud-events-type
= reflector
The emit function appends the metadata and sends the message via the emitter.