如何在不抛出异常的情况下从侦听器显式确认/失败Amazon SQS FIFO队列?

时间:2017-05-29 13:32:02

标签: amazon-sqs

我的应用程序只侦听某个队列,生产者是第三方应用程序。我接收消息但有时基于某些逻辑我需要向生产者发送失败消息,以便消息再次重新发送给我的监听器,直到我决定使用它并确认它。我目前对此过程的实现只是抛出一些自定义异常。但这不是一个干净的解决方案,因此任何人都可以帮助我向生产者发送FAIL而不会抛出异常。

我的JMS侦听器出厂设置:

@Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactoryForQexpress(SQSErrorHandler errorHandler) {
    SQSConnectionFactory connectionFactory = SQSConnectionFactory.builder()
        .withRegion(RegionUtils.getRegion(StaticSystemConstants.getQexpressSqsRegion()))
        .withAWSCredentialsProvider(new ClasspathPropertiesFileCredentialsProvider(StaticSystemConstants.getQexpressSqsCredentials()))
        .build();
    DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
    factory.setConnectionFactory(connectionFactory);
    factory.setDestinationResolver(new DynamicDestinationResolver());
    factory.setConcurrency("3-10");
    factory.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
    factory.setErrorHandler(errorHandler);
    return factory;
}

我的听众设置:

    @JmsListener(destination = StaticSystemConstants.QUEXPRESS_ORDER_STATUS_QUEUE, containerFactory = "jmsListenerContainerFactoryForQexpress")
public void receiveQExpressOrderStatusQueue(String text) throws JSONException {
    LOG.debug("Consumed QExpress status {}", text);
    //here i need to decide either acknowlege or fail
    ...
    if (success) {
         updateStatus();
    } else {
         //todo I need to replace this with explicit FAIL message
         throw new CustomException("Not right time to update status");
    }

}

请分享您的经验。谢谢!

1 个答案:

答案 0 :(得分:1)

SQS--内部说 - 是完全异步的,完全将生产者与消费者分离。

一旦生产者成功地将消息传递给SQS并接收消息ID作为响应,生产者只知道SQS已经接收并将消息提交给其内部存储器,并且消息将至少传递给消费者一次.¹生产者没有进一步的反馈意见。

消费者可以“暂停”消息以便稍后重试,只需不删除它(请参阅setSessionAcknowledgeMode docs)或主动重置消息上的visibility timeout而不是删除消息,这会触发SQS将消息保留在 in flight 状态,直到计时器到期,此时它将再次传递消息以供消费者重试。

另请注意,单个SQS队列可以拥有多个生产者和/或多个消费者,只要所有生产者都要求并且消费者提供相同的服务,但没有内在概念消费者或哪个制作人。没有消费者到生产者的后向通信渠道,也没有生产者查询先前消息状态的机制 - 设计假设是,一旦SQS收到消息,交付,²所以不需要这样的机制。

¹至少一次。除非队列是FIFO队列,否则SQS通常只传递一次消息,但不能绝对保证消息不会多次传递。由于SQS是一个存储冗余消息副本的大型分布式系统,因此可以in some edge case conditions多次传递消息。 FIFO队列通过利用更强的内部一致性保证来避免这种可能性,但代价是降低了300 TPS的吞吐量。

²它将被传递当然假设你实际上有一个消费者正在运行。 SQS不会阻止生产者,并允许您排队等待消费者到达的无限数量的消息。它接受来自生产者的消息,无论当前是否有任何消费者在倾听。消息一直持续到消费或者每个消息的MessageRetentionPeriod(默认4天,最长14天)计时器到期为止,以先发生者为准。