我有一个Spring Boot应用程序来处理来自AWS SQS队列的消息。应用程序发出10条消息请求,启动CountDownLatch
到10,然后将每条消息传递给@Async
方法,该方法返回CompletableFuture
。 CompletableFuture
有thenAccept()
删除消息,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)
有谁能帮助我理解为什么会这样?
答案 0 :(得分:0)
问题的原因被确定为该方法的自定义注释。注释旨在将信息传输到AWS Xray,但是在抛出异常时无意中执行了两次带注释的方法。该机制仍在制定中,但至少我们已确定了罪魁祸首。问题已经更新,因为注释已经停止。