返回CompletableFuture的方法在抛出异常时执行两次

时间:2018-06-07 03:08:51

标签: java spring-boot java-8 completable-future

我有一个Spring Boot应用程序来处理来自AWS SQS队列的消息。应用程序发出10条消息请求,启动CountDownLatch到10,然后将每条消息传递给@Async方法,该方法返回CompletableFutureCompletableFuturethenAccept()删除消息,whenComplete()记录异常(如果有)并递减锁定倒计时。倒计时结束后,将检索下一批消息并重新开始该过程。 当没有异常时,这一切都完美无缺。但是,如果在CompletableFuture方法中抛出异常,则该方法会在返回whenComplete()之前执行两次。

主要方法:

public void readAllMessages(String sqsUrl, MessageConsumer messageConsumer) {
    ReceiveMessageRequest receiveMessageRequest = new ReceiveMessageRequest(sqsUrl).withMaxNumberOfMessages(10);
    List<Message> messages;
    try {
        do {
            messages = amazonSQS.receiveMessage(receiveMessageRequest).getMessages();
            if (CollectionUtils.isNotEmpty(messages)) {
                final CountDownLatch latch = new CountDownLatch(messages.size());
                messages.forEach(message -> {
                    try {
                        messageConsumer.processMessage(message)
                            .thenAccept(m -> {
                                 deleteMessage(sqsUrl, message);
                             })
                             .whenComplete((value, exception) -> {
                                 LOGGER.info("Processing complete for message {}", message.getMessageId());
                                 latch.countDown();
                                 if (exception != null) {
                                     exceptionLogger.logException(String.format("Couldn't process message. queue:%s. id:%s", sqsUrl, message.getMessageId()), exception);
                                 }
                             });
                    } catch (Throwable e) {
                        LOGGER.error("Refreshing tax rate for message {} failed with exception {} ", message.getBody(), e);
                    }
                });
                latch.await();
            } else {
                LOGGER.debug("Queue is empty: '{}'", sqsUrl);
            }
        } while (CollectionUtils.isNotEmpty(messages));
    } catch (InterruptedException e) {
        LOGGER.info("Thread interrupted, stopping.");
    }
}

MessageConsumer.processMessage

@XRayLogged(segmentName = "outdated_host_tax_rate_update")
@Async
@Transactional
@Override
public CompletableFuture<?> processMessage(Message message) {
    OutdatedTaxRateMessage taxRateMessage;
    try {
        taxRateMessage = objectMapper.readValue(message.getBody(), OutdatedTaxRateMessage.class);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
    Long id = taxRateMessage.getHostId();
    LOGGER.info("Updating tax rate. hostId:'{}', messageId:'{}'", id, message.getMessageId());
    hostTaxRateRefreshingService.refreshHostTaxRate(id);
    LOGGER.info("Updated tax rate. hostId:'{}', messageId:'{}'", id, message.getMessageId());
    return CompletableFuture.completedFuture(null);
}

当抛出异常时,&#34;更新税率。 HOSTID:&#39;&#39;&#34;消息被记录两次,然后是来自whenComplete()块的一组消息(&#34;处理完成...&#34;,&#34;无法处理消息......& #34)

有谁能帮助我理解为什么会这样?

1 个答案:

答案 0 :(得分:0)

问题的原因被确定为该方法的自定义注释。注释旨在将信息传输到AWS Xray,但是在抛出异常时无意中执行了两次带注释的方法。该机制仍在制定中,但至少我们已确定了罪魁祸首。问题已经更新,因为注释已经停止。