Apache kafka Spring Cloud Stream>SendTo不发送给卡夫卡,而是直接通过直接渠道发送
在我的应用程序中,有两个频道绑定到两个卡夫卡主题: 输入 error.input.my-group 输入配置为在发生错误时向dlq error.Input.my-group发送消息 我在error.input.my-group上配置了一个StreamListener,用于将消息发送回原始通道Apache kafka Spring Cloud Stream>SendTo不发送给卡夫卡,而是直接通过直接渠道发送,apache-kafka,spring-cloud-stream,Apache Kafka,Spring Cloud Stream,在我的应用程序中,有两个频道绑定到两个卡夫卡主题: 输入 error.input.my-group 输入配置为在发生错误时向dlq error.Input.my-group发送消息 我在error.input.my-group上配置了一个StreamListener,用于将消息发送回原始通道 @StreamListener(Channels.DLQ) @SendTo(Channels.INPUT) public Message<?> reRoute(Message<?>
@StreamListener(Channels.DLQ)
@SendTo(Channels.INPUT)
public Message<?> reRoute(Message<?> failed){
messageDeliveryService.waitUntilCanBeDelivered(failed);
processed.incrementAndGet();
Integer retries = failed.getHeaders().get(X_RETRIES_HEADER, Integer.class);
retries = retries == null ? 1 : retries+1;
if (retries < MAX_RETRIES) {
logger.info("Retry (count={}) for {}", retries, failed);
return buildRetryMessage(failed, retries);
}
else {
logger.error("Retries exhausted (-> sent to parking lot) for {}", failed);
Channels.parkingLot().send(MessageBuilder.fromMessage(failed)
.setHeader(BinderHeaders.PARTITION_OVERRIDE,
failed.getHeaders().get(KafkaHeaders.RECEIVED_PARTITION_ID))
.build());
}
return null;
}
private Message<?> buildRetryMessage(Message<?> failed, int retries) {
return MessageBuilder.fromMessage(failed)
.setHeader(X_RETRIES_HEADER, retries)
.setHeader(BinderHeaders.PARTITION_OVERRIDE,
failed.getHeaders().get(KafkaHeaders.RECEIVED_PARTITION_ID))
.build();
}
问题是我的信息再也不会推送到卡夫卡,而是直接送到我的输入通道。有什么我误解了吗?为了@send到卡夫卡目的地而不是直接发送,您需要一个输出绑定。我不确定我是否理解这个问题。在您的案例中,消息被发送到输出通道输入,但随后绑定器将其发送到主题。虽然您肯定配置错误,但您的问题中没有足够的信息让我们了解它是什么。你能不能把你的项目发布在GitHib或者其他地方,这样我们就可以看一看?就像Oleg一样,我误解了你的问题;我编辑了我的答案,我只是遵循了SpringCloudStream文档中提出的模式。除了没有一个单独的JVM,我在同一个JVM中运行死信队列消耗。为什么我需要一个单独的输入绑定来使用该主题?我想我误解了你的问题;奥列格是对的。为了让@SendTo转到卡夫卡,您需要一个输出目的地,而不是直接发送到输入通道。我只是更新了我的问题,以便提供更多详细信息。我不明白的是,我遵循的文档似乎表明这些消息将使用@SendTo重新发布到卡夫卡主题。我想我明白了。我需要定义:@Outputinput SubscribableChannel input@输出通道输出;这足够了吗?或者我必须使用不同的通道吗?它需要是不同的通道,并且您还需要将输出绑定添加到YML。在文档中,@SendTo表示输出绑定;您直接将其连接到主输入通道。
@Component
public interface Channels {
String INPUT = "INPUT";
//Default name use by SCS (error.<input-topic-name>.<group-name>)
String DLQ = "error.input.my-group";
String PARKING_LOT = "parkingLot.input.my-group";
@Input(INPUT)
SubscribableChannel input();
@Input(DLQ)
SubscribableChannel dlq();
@Output(PARKING_LOT)
MessageChannel parkingLot();
}
spring:
cloud:
stream:
default:
group: my-group
binder:
headerMode: headers kafka:
binder:
# Necessary in order to commit the message to all the Kafka brokers handling the partition -> maximum durability
# -1 = all
requiredAcks: -1
brokers: bootstrap.kafka.svc.cluster.local:9092,bootstrap.kafka.svc.cluster.local:9093,bootstrap.kafka.svc.cluster.local:9094,bootstrap.kafka.svc.cluster.local:9095,bootstrap.kafka.svc.cluster.local:9096,bootstrap.kafka.svc.cluster.local:9097
bindings:
input:
consumer:
partitioned: true
enableDlq: true
dlqProducerProperties:
configuration:
key.serializer: "org.apache.kafka.common.serialization.ByteArraySerializer"
"[error.input.my-group]":
consumer:
# We cannot loose any message and we don't have any DLQ for the DLQ, therefore we only commit in case of success
autoCommitOnError: false
ackEachRecord: true
partitioned: true
enableDlq: false
bindings:
input:
contentType: application/xml
destination: input
"[error.input.my-group]":
contentType: application/xml
destination: error.input.my-group
"[parkingLot.input.my-group]":
contentType: application/xml
destination: parkingLot.input.my-group