应用程序即使接受确认也接受来自Google Pub / Sub的重复消息

时间:2019-12-09 11:42:01

标签: java google-cloud-platform spring-cloud google-cloud-pubsub spring-cloud-gcp

在GCP环境中测试应用程序时,我遇到非常奇怪的浮动bug()。我找不到具体的复制步骤,但确实确实会不时发生。

我看到该消息已成功确认:

2019-12-06 12:37:47.348  INFO 1 --- [sub-subscriber3] .i.g.MyAcknowledgementHandler : Acknowledged message - 1575635858865987

我有以下代码要确认:

        var generation = message.getHeaders().get("objectGeneration");
        pubSubMessage = message.getHeaders().get(GcpPubSubHeaders.ORIGINAL_MESSAGE, BasicAcknowledgeablePubsubMessage.class)
        pubSubMessage.ack().addCallback(
                v -> {
                    removeFromIdempotentStore(targetMessage, false);
                    log.info("Acknowledged message - {}", generation);
                },
                e -> {
                    removeFromIdempotentStore(targetMessage, false);
                    log.error("Failed to acknowledge message - {}", generation, e);
                }
        );

我还看到以下日志:

2019-12-06 12:37:48.868 WARN 1 --- [sub-subscriber1] c.b.m.i.MyDiscardedMessagesHandler : Duplicate message received GenericMessage [... headers={gcp_pubsub_acknowledgement=org.springframework.cloud.gcp.pubsub.integration.inbound.PubSubInboundChannelAdapter$1@1abafe68, bxwid=12345, errorChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@3c3efd63, idempotent.keys=[objectId.mixed emails.csv, objectGeneration.1575635858865987].....

重复无尽。另外,我在订阅图中看到消息仍然存在(在确认回调调用之后)

舍弃逻辑:

....
.gateway(nexrFlow, idempotentByHeader("objectId")); 


Consumer<GatewayEndpointSpec> idempotentByHeader(String objectIdHeader) {
    return endpointSpec -> endpointSpec.advice(idempotentByHeaderInterceptor(objectIdHeader))
            .errorChannel(errorChannel())
            .replyTimeout(0L);
}

default IdempotentReceiverInterceptor idempotentByHeaderInterceptor(String header) {
    MessageProcessor<String> headerSelector = message -> headerExpression(header).apply(message);
    var interceptor = new IdempotentReceiverInterceptor(new MetadataStoreSelector(headerSelector, idempotencyStore()));
    interceptor.setDiscardChannel(idempotentDiscardChannel());
    return interceptor;
}

我不知道如何解决它。有什么想法吗?

1 个答案:

答案 0 :(得分:2)

Pub / sub旨在确保至少传递一个消息,因此这是预期的行为。查看product FAQs以获得官方解释。

如此处所述,频繁重复的原因之一是acknowledgement deadline中没有确认消息。如果处理该消息所花费的时间超过了截止日期,则该消息将被重新发送。这就是为什么我在以前的评论中要求AckDeadline。默认情况下,应为10秒。您可以单击控制台上的订阅,检查如何在控制台中对其进行配置。您可以尝试增加它,以等待更多消息完成处理。只需在订阅中单击一次编辑即可。

但是,即使您在截止日期之前确认,有时也会出现重复。这是保证至少一次交货的必要条件。