是什么原因-“ DLQ支持不适用于匿名订阅”?

时间:2019-07-12 05:43:08

标签: spring spring-boot spring-kafka spring-cloud-stream spring-boot-test

我正在使用依赖项spring-cloud-stream-binder-kafka-streams在SpringBootApplication上工作,并尝试测试发生serdeError时向Dlq发送错误消息。

@Slf4j
@Component
@EnableBinding(KafkaBinding.class)
public class AListener {

      @StreamListener
      public void sink(@Input(KafkaBinding.ABINDING) KStream<String, AnOrder> events) {
        log.info("HERE_BEFORE");
        events.foreach((k, v) -> {
          log.info("HERE_AFTER value: {}", v.toString());
          throw new RuntimeException("Failed, should land in dlq topic");
        });
      }
    }
public interface KafkaBinding {
  String ABINDING = "some.events";

  @Input(ABINDING)
  public KStream<String, AnOrder> incomingOrder();
}

application.yml

spring:
  application:
    name: aprocessor
  cloud:
    stream:
      kafka:
        streams:
          binder:
            brokers: localhost:9092
            serdeError: sendToDlq
            configuration:
              commit.interval.ms: 1000
              default:
                key.serde: org.apache.kafka.common.serialization.Serdes$StringSerde
                value.serde: org.apache.kafka.common.serialization.Serdes$StringSerde
          bindings:
            input:
              consumer:
                enableDlq: true
                dlqName: a-dlq
                autoCommitOnError: true
                autoCommitOffset: true
      bindings:
        input:
          group: a-group
          destination: some.events
        pos:
          destination: some.events
          consumer.header-mode: raw

测试:

@Slf4j
@DirtiesContext
@SpringBootTest
@EmbeddedKafka(
    partitions = 1,
    topics = {"some.events"},
    controlledShutdown = true,
    brokerProperties = {
      "listeners=PLAINTEXT://localhost:9092",
      "port=9092",
      "auto.create.topics.enable=${topics.autoCreate:false}",
      "delete.topic.enable=${topic.delete:true}"
    })
public class AListenerTest {
  private KafkaTemplate<String, String> kafkaTemplate;

  @Autowired private EmbeddedKafkaBroker embeddedKafka;
  @SpyBean private AListener listener;

  private static final String INPUT_TOPIC = "some.events";

  @BeforeEach
  public void setUp() {

    Map<String, Object> senderProperties =
        KafkaTestUtils.senderProps(embeddedKafka.getBrokersAsString());

    ProducerFactory<String, String> producerFactory =
        new DefaultKafkaProducerFactory<>(senderProperties);

    kafkaTemplate = new KafkaTemplate<>(producerFactory);

    kafkaTemplate.setDefaultTopic(INPUT_TOPIC);
  }

  @Test
  public void whenExceptionInConsumer_thenLogToDLQ(){
    String logme = "{\"body\":\"thor\"}";
    kafkaTemplate.sendDefault(logme);
    log.info("<<<<DATA>>>> {}", logme);
  }
}

测试失败,并显示以下堆栈跟踪:

Caused by: org.springframework.context.ApplicationContextException: Failed to start bean 'inputBindingLifecycle'; nested exception is java.lang.IllegalArgumentException: DLQ support is not available for anonymous subscriptions
    at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:185)
    at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:53)
    at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:360)
    at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:158)
    at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:122)
    at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:893)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:552)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:316)
    at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:127)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:117)
    ... 54 more
Caused by: java.lang.IllegalArgumentException: DLQ support is not available for anonymous subscriptions
    at org.springframework.util.Assert.isTrue(Assert.java:118)
    at org.springframework.cloud.stream.binder.kafka.provisioning.KafkaTopicProvisioner.doProvisionConsumerDestination(KafkaTopicProvisioner.java:186)
    at org.springframework.cloud.stream.binder.kafka.provisioning.KafkaTopicProvisioner.provisionConsumerDestination(KafkaTopicProvisioner.java:161)
    at org.springframework.cloud.stream.binder.kafka.streams.KafkaStreamsBinderUtils.prepareConsumerBinding(KafkaStreamsBinderUtils.java:53)
    at org.springframework.cloud.stream.binder.kafka.streams.KStreamBinder.doBindConsumer(KStreamBinder.java:93)
    at org.springframework.cloud.stream.binder.kafka.streams.KStreamBinder.doBindConsumer(KStreamBinder.java:51)
    at org.springframework.cloud.stream.binder.AbstractBinder.bindConsumer(AbstractBinder.java:142)
    at org.springframework.cloud.stream.binding.BindingService.doBindConsumer(BindingService.java:144)
    at org.springframework.cloud.stream.binding.BindingService.bindConsumer(BindingService.java:112)
    at org.springframework.cloud.stream.binding.BindableProxyFactory.createAndBindInputs(BindableProxyFactory.java:254)
    at org.springframework.cloud.stream.binding.InputBindingLifecycle.doStartWithBindable(InputBindingLifecycle.java:58)
    at java.base/java.util.LinkedHashMap$LinkedValues.forEach(LinkedHashMap.java:608)
    at org.springframework.cloud.stream.binding.AbstractBindingLifecycle.start(AbstractBindingLifecycle.java:48)
    at org.springframework.cloud.stream.binding.InputBindingLifecycle.start(InputBindingLifecycle.java:34)
    at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:182)
    ... 66 more

我希望测试成功,控制台日志显示已创建dlq / topic,并查询dlq以打印消息。是什么导致KafkaTopicProvisioner抛出“ IllegalArgumentException:DLQ支持不适用于匿名订阅”?

我已经尝试过本文中提到的步骤“ Correctly manage DLQ in Spring Cloud Stream Kafka”。

1 个答案:

答案 0 :(得分:1)

不允许匿名使用者使用DLQ;您需要为此进行永久订阅。

匿名使用者是未指定使用者组的使用者。

根据您引用的答案。

  bindings:
    input:
      group: so51247113

此外,这是开源的,您可能已经看过KafkaTopicProvisioner ...... p

    boolean anonymous = !StringUtils.hasText(group);
    Assert.isTrue(!anonymous || !properties.getExtension().isEnableDlq(),
            "DLQ support is not available for anonymous subscriptions");