Spring Cloud Streams kafka binder - topic serialization configuration - spring

So I think I've run myself into confusion as I understand there are two different kafka binders for SpringCloudStreams:
Spring Cloud Streams Kafka Binder
Spring Cloud Streams Kafka Streams Binder
I'm looking for the correct YAML settings to define the serializer and deserializer in the normal kafka binder for spring cloud streams:
I can tweak the defaults using this logic:
spring:
main:
web-application-type: NONE
application:
name: tbfm-translator
kafka:
consumer:
group-id: ${consumer_id}
bootstrap-servers: ${kafka_servers}
cloud:
schemaRegistryClient:
endpoint: ${schema_registry}
stream:
# default:
# producer.useNativeEncoding: true
# consumer.useNativeEncoding: true
defaultBinder: kafka
kafka:
binder:
auto-add-partitions: true # I wonder if its cause this is set
auto-create-topics: true # Disabling this seem to override the server setings and will auto create
producer-properties:
# For additional properties you can check here:
# https://docs.confluent.io/current/installation/configuration/producer-configs.html
schema.registry.url: ${schema_registry}
# Disable for auto schema registration
auto.register.schemas: false
# Use only the latest schema version
use.latest.version: true
# This will use reflection to generate schemas from classes - used to validate current data set
# against the scheam registry for valid production
schema.reflection: true
# To use an avro key enable the following line
#key.serializer: io.confluent.kafka.serializers.KafkaAvroSerializer
#This will use a string based key - aka not in the registry - dont need a name strategy with string serializer
key.serializer: org.apache.kafka.common.serialization.StringSerializer
# This will control the Serializer Setup
value.subject.name.strategy: io.confluent.kafka.serializers.subject.RecordNameStrategy
value.serializer: io.confluent.kafka.serializers.KafkaAvroSerializer
which is:
spring.cloud.stream.kafka.binder.producer-properties.value.serializer
spring.cloud.stream.kafka.binder.producer-properties.key.serializer
I figure I should be able to do this on a per-topic basis:
spring:
cloud:
stream:
bindings:
my-topic:
destination: a-topic
xxxxxxxx??
I've come across setting:
producer:
use-native-encoding: false
keySerde: <CLASS>
But this doesn't seem to be working. Is there an easy property I can set to do this on the per-topic basis? I think the keySerde is for the Kafka-streams implementation not the normal kafka binder.

use-native-encoding must be true to use your own serializers.
spring.cloud.stream.kafka.bindings.my-topic.producer.configuration.value.serializer: ...
See the documentation for kafka-specific producer properties.
configuration
Map with a key/value pair containing generic Kafka producer properties.
Default: Empty map.

stream:
bindings: # Define output topics here and then again in the kafka.bindings section
test:
destination: multi-output
producer:
useNativeDecoding: true
kafka:
bindings:
test:
destination: multi-output
producer:
configuration:
value.serializer: org.apache.kafka.common.serialization.StringSerializer
This seems to work - but very annoying I have to duplicate the binding definition in two places
Makes we want to shy away from the YAML style definition

Related

Spring cloud stream producer retries and error handling

I have set a spring cloud stream kafka producer and consumer and there are 3 kafka brokers running . I have set min.insync.replicas to 4 to see how producer error handling works . The messagechannel.send call returns immediately and the producer logs keep saying NOT_ENOUGH_REPLICAS which is fine and expected .
server.port: 9050
spring:
cloud:
stream:
bindings:
errorChannel:
destination: error-topic
output:
destination: stream-topic
group: top-group
producer:
errorChannelEnabled: true
kafka:
bindings:
output:
producer:
retries: 3
sync: false
binder:
autoCreateTopics: true
configuration:
value:
serializer: com.example.kafkapublisher.MySerializer
producer-properties:
acks: all
spring.cloud.stream.kafka.bindings.errorChannel.consumer.enableDlq: true
The above is my producer configuration . Although retries is set to 3 , the producer keeps on retrying a large number of times . Although sync is set to true , the send call comes out immediately . Although error channel and destination is defined , and errorChannelEnabled is set to true i do't see the failed message in the error topic my-error, neither is the error topic created . Request your help
Arbitrary Kafka producer properties go in the ...producer.configuration property.
https://docs.spring.io/spring-cloud-stream/docs/current/reference/html/spring-cloud-stream-binder-kafka.html#kafka-producer-properties
configuration
Map with a key/value pair containing generic Kafka producer properties. The bootstrap.servers property cannot be set here; use multi-binder support if you need to connect to multiple clusters.
Default: Empty map.

Spring Cloud Stream: Cannot connect to 2 rabbitmq clusters without allowOverride

I have a spring boot application (let's call it example-service) with the following configuration to connect to 2 different rabbitmq clusters.
spring:
cloud:
stream:
defaultBinder: rabbitA
binders:
rabbitA:
inheritEnvironment: false
defaultCandidate: false
type: rabbit
environment:
spring:
rabbitmq:
addresses: rabbitmq-a:5672
username: user-a
password: password-a
rabbitB:
inheritEnvironment: false
defaultCandidate: false
type: rabbit
environment:
spring:
rabbitmq:
addresses: rabbitmq-b:5672
username: user-b
password: password-b
bindings:
dataFromA:
destination: exchange-1
group: queue-1
binder: rabbitA
dataFromB:
destination: exchange-2
group: queue-2
binder: rabbitB
That itself works fine, it connects to both clusters. The problem is that this service is deployed in an environment where there is a spring config server with the following files:
application.yml
spring.rabbitmq:
addresses: rabbitmq-a:5672
username: user-a
password: password-a
Then that seems to override the configuration set for each binder, located under the "environment" property. So I needed to add this extra config.
example-service.yml
spring.cloud:
config:
overrideSystemProperties: false
allowOverride: true
overrideNone: false
Now the example-service connects to both rabbitmq clusters again. But I have observed certain side effects, mainly not being able to override other properties in the config server example-service.yml anymore, which is a real need for me. So I have discarded using allowOverride and its related properties.
The question is... is it possible to make it work without using allowOverride, while keeping the spring.rabbitmq.addresses/username/password in the remote config server application.yml?
Thank you very much in advance.
Kind regards.
Which version are you using? I just tested it with 3.0.6 and it works fine:
spring:
cloud:
stream:
binders:
rabbitA:
type: rabbit
inherit-environment: false
environment:
spring:
rabbitmq:
virtual-host: A
rabbitB:
type: rabbit
inherit-environment: false
environment:
spring:
rabbitmq:
virtual-host: B
bindings:
input1:
binder: rabbitA
destination: input1
group: foo
input2:
binder: rabbitB
destination: input2
group: bar
rabbitmq:
virtual-host: /
Probably not related, but your group indentation is wrong.

How to define multiple packages as trusted package in yaml

I have a Spring boot application where I am consuming data from Kafka topics.
For the Objects which I consume, I need to provide their package names as trusted packages.
eg.
spring:
kafka:
consumer:
bootstrap-servers: localhost:9092
group-id: group_id
auto-offset-reset: earliest
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
properties:
spring:
json:
trusted:
packages: com.sample.cassandra
Now I have multiple packages which I need to define as trusted package.
For example I have com.sample.demo, but when I try something like this:
spring:
json:
trusted:
packages: com.sample.cassandra, com.sample.demo
It doesn't work.
What would be the correct syntax to define multiple packages in the yaml file?
The YAML syntax for sequences is
packages: [com.sample.cassandra, com.sample.demo]
You can alternatively use the block syntax:
packages:
- com.sample.cassandra
- com.sample.demo

SCDF kubernetes custom source is writing data to "ouput" channel

I have custom source application which reads data from external kafka server and pass the information to next processor in the stream. In local everything works perfect. I have created docker image of the code and when i deploy stream in kubernetes env, i do see topic with the name stream.source-app got created but messages produced by source are actually going to "output" topic. I dont see this issue in local env.
application.yaml
spring:
cloud:
stream:
bindings:
Workitemconnector_subscribe:
destination: Workitemconnector
contentType: application/json
group: SCDFMessagingSourceTestTool1
consumer:
partitioned: true
concurrency: 1
headerMode: embeddedHeaders
output:
# destination: dataOut
binder: kafka2
binders:
kafka1:
type: kafka
environment:
spring:
cloud:
stream:
kafka:
binder:
brokers: xx.xxx.xx.xxx:9092
zkNodes: xx.xxx.xx.xxx:2181
kafka2:
type: kafka
environment:
spring:
cloud:
stream:
kafka:
binder:
brokers: server1:9092
zkNodes: server1:2181
spring.cloud.stream.defaultBinder: kafka1
In local without defining any parameters during stream deployment, i notice source is consuming message from xxxx server and producing data to server1 and to the topic name "stream.sourceapp" but in kubernetes env it is acting strange. It is always sending data to "output" topic even though "stream.sourceapp" topic exists

Multiple bindingRoutingKey's for a consumer with Spring Cloud Stream using RabbitMQ

I'd like to configure an input channel in Spring Cloud Stream to be bound to the same exchange (destination) with multiple routing keys. I've managed to get this working with a single routing key like this:
spring:
cloud:
stream:
rabbit:
bindings:
input1:
consumer:
bindingRoutingKey: key1.#
bindings:
input1:
binder: rabbit
group: group1
destination: dest-group1
But I cannot seem to get it working for multiple keys. I've tried this:
spring:
cloud:
stream:
rabbit:
bindings:
input1:
consumer:
bindingRoutingKey: key1.#,key2.#
bindings:
input1:
binder: rabbit
group: group1
destination: dest-group1
But this doesn't seem to work.
I'm using Spring Boot 2.0.1 and Spring cloud dependencies are imported from:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.RC1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
Does anyone know how to achieve this?
This can be done now by adding a property:
spring.cloud.stream.rabbit.bindings.<channel-name>.consumer.binding-routing-key-delimiter=,
Then you can comma separate the routing keys:
spring.cloud.stream.rabbit.bindings.<channel-name>.consumer.binding-routing-key=key1,key2,key3
Thanks Gary
Reference documentation
It can't be done with properties; but you can declare the additional bindings as beans; see this answer.
There is also a third party "advanced" boot starter that allows you to add declarations in a yaml file. I haven't tried it, but it looks interesting.

Resources