SQS in SpringBoot Acknowledge Mode

반응형
Acknowledge를 하지 않았는데 왜 메시지가 잘 소비되고 있는거지?

Simple Queue Service

 

Spring Boot에서 SQS를 사용하는 경우 다음과 같은 AWS + JMS 설정이 필요하다.

    @Bean
    fun jmsListenerContainerFactory(): DefaultJmsListenerContainerFactory {
        log.info { "SQS Consumer auto start ${sqsEnabled.toBoolean()}" }
        val factory = DefaultJmsListenerContainerFactory()
        factory.setConnectionFactory(sqsConnectionFactory)
        factory.setDestinationResolver(DynamicDestinationResolver())
        factory.setConcurrency("3-10")
        factory.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE)
        factory.setAutoStartup(sqsEnabled.toBoolean())
        return factory
    }

여기서 확인해볼 것은 Session Ack Mode이다. JMS에서 제공하는 기본 모드는 크게 3가지이다.

  • AUTO_ACKNOWLEDGE
  • CLIENT_ACKNOWLEGE
  • DUPS_OK_ACKNOWLEDGE
  • SESSION_TRANSACTED

이중 오해를 살만한 값이 두번째 모드인 "Client Acknowledge" 모드이다. 의미상으로만 보면 마치 클라이언트 단에서 직접 Ack를 보야지만 메시지 처리가 되는 것처럼 설명이 되어있다. 그러나 실제로 사용할 때는 ack 메소드를 호출하지 않더라도 메시지가 소비되는 것을 볼 수 있다.

    @JmsListener(destination = "\${app.consumer.sqs.response}")
    fun jmsListener(jmsMessage: Message) {
        //Do something
        //jmsMessage.acknowledge()
    }

이와 관련해서 의문을 풀어줄 수 있는 내용이 있어 공유한다.

https://jira.spring.io/browse/SPR-13255?redirect=false

 

CLIENT_ACKNOWLEDGE with JmsTemplate - implicit message acknowledge each read [SPR-13255] · Issue #17846 · spring-projects/spri

Lubos Krnac opened SPR-13255 and commented I found this code in JmsTemplate.doReceive(Session session, MessageConsumer consumer): Message message = doReceive(consumer, timeout); if (session.getTran...

github.com

https://jira.spring.io/browse/SPR-13255?redirect=false
Since we recently fine-tuned our documentation on JMS acknowledge modes (#17869), this should hopefully be clearer now: Not just in listener containers but also in JmsTemplate, CLIENT_ACKNOWLEDGE is just a mode of processing each message, essentially as an alternative to transactional acknowledgment.
Since we don't hold on to the same JMS Session there but rather re-acquire one for each message, manual acknowledgment in application code is not feasible here. For custom acknowledgment of a series of messages, you'd need to avoid JmsTemplate and perform direct invocations on an explicitly acquired JMS Session there, manually releasing it at the very end.

 

결론적으로 JMS Template을 사용할 경우, Client Ack 모드는 메시지를 건건히 처리할 수 있는 모드를 가리킨다. JMS Template의 경우 아래 소스코드에서 볼 수 있듯이 doRecieved() 메소드에서 isClientAcknowledge(session) 인 경우 message.acknowledge()를 자동으로 호출한다.

https://github.com/spring-projects/spring-framework/blob/main/spring-jms/src/main/java/org/springframework/jms/core/JmsTemplate.java

 

 

GitHub - spring-projects/spring-framework: Spring Framework

Spring Framework. Contribute to spring-projects/spring-framework development by creating an account on GitHub.

github.com

헷갈리게하는 부분은 SQS Document의 설명과 내용이 다르기 때문이다. SQS Document에서는 Client Ack 모드를 Client에서 명시적으로 Ack를 해줘야하는 모드로 설명을 한다. 맞는 말이다. 그런데 이것은 AWS SDK의 Session을 곧장 사용했을 경우이다.

https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/getting-started.html#using-client-acknowledge-mode

 

Getting started with the Amazon SQS Java Messaging Library - Amazon Simple Queue Service

In this mode, when a message is acknowledged, all messages received before this message are implicitly acknowledged as well. For example, if 10 messages are received, and only the 10th message is acknowledged (in the order the messages are received), then

docs.aws.amazon.com

 

반응형

'Backend > Spring' 카테고리의 다른 글

Spring Data Projection 기능 활용  (0) 2022.02.13