Zecrates
Zecrates

Reputation: 2982

Only send JMS message once the JPA transaction commits

I'm working on a project that makes use of Spring's JmsTemplate, ActiveMQ and Hibernate. I have a method wrapped in a transaction which sends a message through the JmsTemplate, does a bit more work and then returns so that the transaction can commit. I want the message to only be sent once the transaction commits, i.e. the JmsListener should only trigger once the aforementioned method returns.

Take the following example sender and receiver:

@Service
@Transactional
public class TestService{

  @Autowired
  private JmsTemplate jmsTemplate;

  public void test() throws InterruptedException {
    jmsTemplate.convertAndSend("test_queue", "Test");
    Thread.sleep(1000L);
    System.out.println("This should run first");
  }
}

@Service
@Transactional
public class Listener {

  @JmsListener(destination = "test_queue", containerFactory = "jmsListenerContainerFactory")
  public void onMessage() {
    System.out.println("This should run last.");
  }
}

I want the text "This should run first" to print before "This should run last", but because of the Thread.sleep it never does! I tried a number of changes to the configuration on my jmsListenerContainerFactory, but none make any difference.

Not sure if XA is involved in this case. Is the actual send of the message part of a separate transaction? If so the issue is probably that the two transactions aren't synchronizing, but I don't know how to solve that.

Upvotes: 3

Views: 1854

Answers (1)

Zecrates
Zecrates

Reputation: 2982

I had to set Session Transacted on JmsTemplate instead of JmsListenerContainerFactory:

@Bean
public JmsTemplate jmsTemplate(ConnectionFactory connectionFactory) {
    JmsTemplate jmsTemplate = new JmsTemplate(connectionFactory);
    jmsTemplate.setSessionTransacted(true);
    return jmsTemplate;
}

Upvotes: 2

Related Questions