prosource

JMS 메시지가 사용될 때까지 스프링 컨텍스트 유지

probook 2023. 7. 22. 10:11
반응형

JMS 메시지가 사용될 때까지 스프링 컨텍스트 유지

는 다과관련꽤표있설습다니정이인준음과 관련된 꽤 인 설정을 가지고 있습니다.JMS-Spring Boot그리고.ActiveMQ간단한 통합 테스트를 시도하기 전까지는 잘 작동합니다.몇 가지 조사를 해본 결과, 첫 번째 JMS 메시지가 사용된 후 Spring 컨텍스트와 포함된 브로커가 모두 닫혔으며, 사용 중에 다른 이벤트가 발생했음에도 불구하고.브로커 문제를 추가하여 해결할 수 있었습니다.useShutdownHook=false테스트 설정의 연결 옵션, 즉.

spring.activemq.broker-url = vm://broker?async=false&broker.persistent=false&broker.useShutdownHook=false

제가 찾고 있는 것은 기본적으로 모든 JMS 메시지가 소비될 때까지 테스트를 "계속 유지"하도록 강제하는 방법입니다(이 경우에는 두 개뿐입니다).전체 설정의 비동기성을 이해하지만 테스트 중에 이러한 메시지가 생성되고 소비되는 모든 결과를 얻는 것이 도움이 될 것입니다.

아래는 간단한 설정입니다.

@EnableJms
public class ActiveMqConfig {

    @Bean
    public JmsTemplate jmsTemplate(ConnectionFactory connectionFactory, MessageConverter messageConverter) {
        JmsTemplate jmsTemplate = new JmsTemplate(connectionFactory);
        jmsTemplate.setMessageConverter(messageConverter);
        return jmsTemplate;
    }

    @Bean
    public MessageConverter messageConverter() {
        MappingJackson2MessageConverter messageConverter = new MappingJackson2MessageConverter();
        messageConverter.setTargetType(MessageType.TEXT);
        messageConverter.setTypeIdPropertyName("_type");
        return messageConverter;
    }
}

그런 다음 특정 이벤트를 수신하는 메시지 기반 POJO가 있습니다.

@JmsListener(destination = "events")
public void applicationSubmitted(MyType event) {
    // do some work with the event here

    jmsTemplate.convertAndSend("commands", mymessage);
}

그리고 또 하나:

@JmsListener(destination = "commands")
public void onCommand(TextMessage textMessage) {

}

제가 시도해 본 한 가지는 지연을 추가하는 것입니다.sleep(200)메시지가 전송된 후.그러나 실행 시간이 50ms 미만이기 때문에 매우 신뢰할 수 없고 테스트 속도도 느려집니다.아래는 테스트 자체입니다.대기에 대한 설명이 없는 한, 응용 프로그램 컨텍스트가 닫히면 테스트가 종료되고 메시지가 "잊혀진" 상태가 됩니다.

@SpringBootTest
class MyEventIntegrationTest extends Specification {

    @Autowired
    JmsTemplate jmsTemplate

    def "My event is successfully handled"() {

        given:
        def event = new MyEvent()

        when:
        jmsTemplate.convertAndSend("events", event)
        // sleep(200)

        then:
        1 == 1
    }
}

이것은 비동기 메시지 교환을 기반으로 시스템을 테스트할 때 일반적인 문제입니다.보통, 그것은 당신이 건너뛰었던 시험 부분에서 해결됩니다 - 더.then일부.

중요한 것은 테스트에서 시스템이 DB 변경, 다른 시스템으로 정지 호출 보내기, 다른 대기열로 메시지 보내기 등과 같은 유용한 작업을 수행하기를 기대한다는 것입니다.결과를 지속적으로 확인하여 결과가 발생할 때까지 시간을 기다릴 수 있습니다(설정한 시간 범위 내에 결과가 달성된 경우). 그러면 테스트가 통과되었다고 가정할 수 있습니다.

이 접근법의 유사 코드는 다음과 같습니다.

for (i to MAX_RETRIES; i++) {
   checkThatTheChangesInDBHasBeenMade();
   checkThatTheRestCallHasBeenMade();
   checkThatTheMessageIsPostedInAnotherQueue();

   Thread.sleep(50ms);
}

이 방법을 사용하면 50ms 내에 테스트를 통과할 수 있습니다.더 나쁜 경우에는 실패하고 테스트를 실행하는 데 MAX_RETRIES * 50ms 시간이 걸립니다.

또한 비동기 세계에서 이러한 종류의 문제를 처리할 수 있는 멋진 API(btw는 groovy DSL을 지원함)를 제공하는 waitability라는 좋은 도구가 있다는 것을 언급해야 합니다.

await().atMost(5, SECONDS).until(customerStatusIsUpdated());

저는 당신의 문제의 근본은 비동기식 이벤트 처리라고 생각합니다.이벤트를 보내고 나면 테스트가 막 종료됩니다.물론 이것은 스프링 컨텍스트와 브로커를 종료하게 할 것입니다.JMS 수신기가 다른 스레드에서 실행되고 있습니다.당신은 그들을 기다릴 방법을 찾아야 합니다.그렇지 않으면 스레드(테스트 케이스)가 완료된 것입니다.

우리는 지난 프로젝트에서 비슷한 문제에 직면했고 작은 유틸리티를 작성하여 많은 도움을 주었습니다.JMS는 대기열을 "찾아보고" 비어 있는지 확인할 수 있는 기능을 제공합니다.

public final class JmsUtil {

    private static final int MAX_TRIES = 5000;
    private final JmsTemplate jmsTemplate;

    public JmsUtil(JmsTemplate jmsTemplate) {
        this.jmsTemplate = jmsTemplate;
    }

    private int getMessageCount(String queueName) {
        return jmsTemplate.browseSelected(queueName, "true = true", (s, qb) -> Collections.list(qb.getEnumeration()).size());
    }

    public void waitForAll(String queueName) {
        int i = 0;
        while (i <= MAX_TRIES) {
            if (getMessageCount(queueName) == 0) {
                return;
            }
            i++;
        }
}

이 유틸리티를 사용하면 다음과 같은 작업을 수행할 수 있습니다.

def "My event is successfully handled"() {

        given:
        def event = new MyEvent()

        when:
        jmsTemplate.convertAndSend("events", event)
        jmsUtility.waitForAll("events"); // wait until the event has been consumed
        jmsUtility.waitForAll("commands"); // wait until the command has been consumed

        then:
        1 == 1
    }

참고: 이 유틸리티는 사용자가 JMS 메시지를 큐로 보낸다고 가정합니다.대기열을 탐색하여 비어 있는지 확인할 수 있습니다.항목의 경우 다른 검사를 수행해야 할 수 있습니다.그러니 그것을 알아두세요!

언급URL : https://stackoverflow.com/questions/49283280/keep-spring-context-alive-until-jms-messages-are-consumed

반응형