2017-05-24 4 views
0

ActiveMQ (버전 5.14.5) 대기열에서 JMS 메시지를 사용하기위한 간단한 Spring 부트 응용 프로그램 (스프링 부트 버전 1.5.3.RELEASE)이 있습니다.Spring JMS 트랜잭션 롤백 - 메시지가 ActiveMQ에서 대기열에서 제외되었습니다.

메시지를 JMS 트랜잭션에서 사용하려고합니다. 메시지 소비 중에 예외가 발생하면 트랜잭션이 롤백되고 대기열에서 제외되지 않을 것으로 예상됩니다 (메시지 대기열에서 제거됨). 트랜잭션이 Spring 로그에서 롤백되는 것을 볼 수 있지만, 메시지는 여전히 6 회의 재 전달 시도 후에 ActiveMQ 큐에서 대기열에서 제외됩니다.

모든 포인터가 제공됩니다. ActiveMQ는 메시지를 다시 따르면

2017-05-24 09:51:59.865 DEBUG 8972 --- [DefaultMessageListenerContainer-1] o.s.j.connection.JmsTransactionManager : Created JMS transaction on Session [ActiveMQSession {id=ID:D6C0B8467A518-58248-1495590693980-1:32:1,started=false} [email protected]] from Connection [ActiveMQConnection 
2017-05-24 09:51:59.867 DEBUG 8972 --- [DefaultMessageListenerContainer-1] o.s.j.l.DefaultMessageListenerContainer : Received message of type [class org.apache.activemq.command.ActiveMQTextMessage] from consumer [ActiveMQMessageConsumer { value=ID:D6C0B8467A518-58248-1495590693980-1:32:1:1, started=true }] of transactional session [ActiveMQSession {id=ID:D6C0B8467A518-58248-1495590693980-1:32:1,started=true} [email protected]] 
2017-05-24 09:51:59.867 DEBUG 8972 --- [DefaultMessageListenerContainer-1] o.s.j.l.DefaultMessageListenerContainer : Rolling back transaction because of listener exception thrown: org.springframework.jms.listener.adapter.ListenerExecutionFailedException: Listener method 'public void com.anz.markets.springjmsdemo.Receiver.receiveMessage(java.lang.String)' threw exception; nested exception is java.lang.RuntimeException: nooo 
2017-05-24 09:51:59.867 WARN 8972 --- [DefaultMessageListenerContainer-1] o.s.j.l.DefaultMessageListenerContainer : Execution of JMS message listener failed, and no ErrorHandler has been set. 

org.springframework.jms.listener.adapter.ListenerExecutionFailedException: Listener method 'public void com.anz.markets.springjmsdemo.Receiver.receiveMessage(java.lang.String)' threw exception; nested exception is java.lang.RuntimeException: nooo 
    at org.springframework.jms.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:112) ~[spring-jms-4.3.8.RELEASE.jar:4.3.8.RELEASE] 
    at org.springframework.jms.listener.adapter.MessagingMessageListenerAdapter.onMessage(MessagingMessageListenerAdapter.java:69) ~[spring-jms-4.3.8.RELEASE.jar:4.3.8.RELEASE] 
    at org.springframework.jms.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:721) ~[spring-jms-4.3.8.RELEASE.jar:4.3.8.RELEASE] 
    at org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:681) ~[spring-jms-4.3.8.RELEASE.jar:4.3.8.RELEASE] 
    at org.springframework.jms.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:651) ~[spring-jms-4.3.8.RELEASE.jar:4.3.8.RELEASE] 
    at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:317) [spring-jms-4.3.8.RELEASE.jar:4.3.8.RELEASE] 
    at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:235) [spring-jms-4.3.8.RELEASE.jar:4.3.8.RELEASE] 
    at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1166) [spring-jms-4.3.8.RELEASE.jar:4.3.8.RELEASE] 
    at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1158) [spring-jms-4.3.8.RELEASE.jar:4.3.8.RELEASE] 
    at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:1055) [spring-jms-4.3.8.RELEASE.jar:4.3.8.RELEASE] 
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_72] 
Caused by: java.lang.RuntimeException: nooo 
    at com.anz.markets.springjmsdemo.Receiver.receiveMessage(Receiver.java:12) ~[classes/:na] 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_72] 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_72] 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_72] 
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_72] 
    at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:180) ~[spring-messaging-4.3.8.RELEASE.jar:4.3.8.RELEASE] 
    at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:112) ~[spring-messaging-4.3.8.RELEASE.jar:4.3.8.RELEASE] 
    at org.springframework.jms.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:104) ~[spring-jms-4.3.8.RELEASE.jar:4.3.8.RELEASE] 
    ... 10 common frames omitted 

2017-05-24 09:51:59.868 DEBUG 8972 --- [DefaultMessageListenerContainer-1] o.s.j.connection.JmsTransactionManager : Transactional code has requested rollback 
2017-05-24 09:51:59.868 DEBUG 8972 --- [DefaultMessageListenerContainer-1] o.s.j.connection.JmsTransactionManager : Initiating transaction rollback 
2017-05-24 09:51:59.868 DEBUG 8972 --- [DefaultMessageListenerContainer-1] o.s.j.connection.JmsTransactionManager : Rolling back JMS transaction on Session [ActiveMQSession {id=ID:D6C0B8467A518-58248-1495590693980-1:32:1,started=true} [email protected]] 
+0

에게 그것을 메시지가 재전송 시도 및 트랜잭션 롤백에 실패한 후 메시지가 기본 배달 못 한 편지 대기열로 이동 한 ActiveMQ 기능에 나타납니다 – kb1

+0

ActiveMQ 브로커 로그를 확인하고 브로커가 메시지를 "롤백"하는 것을 볼 수 있지만 롤백의 효과는 나타납니다 대기열에 보관되는 것이 아니라 대기열에 보관되는 것보다 메시지가 대기열에 보관되는 것인가? 관리 콘솔에 기본 데드 레터 채널 대기열이 표시되지 않음 – kb1

+0

메시지가 Dead L로 라우팅되지 않도록 ActiveMQ Broker를 구성 할 수 있습니까? etter Queue하지만 트랜잭션 롤백의 경우 원래 대기열에 대기열에 남아 있습니까? 응용 프로그램 영구 저장소 (db)가 다운 된 시나리오에서 메시지를 거래 편지 대기열로 이동하지 않고 대기열에 보관하는 것이 좋습니다. – kb1

답변

0

: 로그

@SpringBootApplication 
public class SpringJmsDemoApplication { 
public static void main(String[] args) { 
     SpringApplication.run(SpringJmsDemoApplication.class, args); 
    } 

    @Bean 
    public JmsListenerContainerFactory<?> myFactory(ConnectionFactory connectionFactory, 
      DefaultJmsListenerContainerFactoryConfigurer configurer) { 
     DefaultJmsListenerContainerFactory defaultJmsListenerContainerFactory = new DefaultJmsListenerContainerFactory(); 
     defaultJmsListenerContainerFactory.setTransactionManager(jmsTransactionManager(connectionFactory)); 
     defaultJmsListenerContainerFactory.setSessionTransacted(true); 
     defaultJmsListenerContainerFactory.setSessionAcknowledgeMode(Session.SESSION_TRANSACTED); 
     configurer.configure(defaultJmsListenerContainerFactory, connectionFactory); 
     return defaultJmsListenerContainerFactory; 
    } 

    @Bean 
    public PlatformTransactionManager jmsTransactionManager(ConnectionFactory connectionFactory) { 
     return new JmsTransactionManager(connectionFactory); 
    } 
} 

@Component 

공용 클래스 수신기 {

@JmsListener(destination = "mailbox", containerFactory = "myFactory") 
@Transactional 
public void receiveMessage(String email) { 
    System.out.println("Received <" + email + ">"); 
    throw new RuntimeException("nooo"); 
} 

} 여기

된다 : 여기

응용 프로그램 코드 - 디 ( http://activemq.apache.org/message-redelivery-and-dlq-handling.html) :

"ActiveMQ의 기본 배달 못 한 편지 대기열은 ActiveMQ.DLQ라고합니다. 배달 할 수없는 모든 메시지는이 대기열로 보내지며 관리하기가 어려울 수 있습니다. 따라서 activemq.xml 구성 파일의 대상 정책 맵에 individualDeadLetterStrategy을 설정하면 주어진 대기열 또는 주제에 대해 특정 데드 레터 대기열 접두사를 지정할 수 있습니다. "아래의 예와 같이

하십시오이 큐에 individualDeadLetterStrategy 당신에게 activemq.xml을 확장한다대로, 모든 큐가 자신의 데드 - 레터 큐를 얻을 수 있도록 좋아하는 경우에 당신은 와일드 카드를 사용하여이 전략을 적용 할 수 있습니다.