2

I know there are a lot a of questions about message driven beans and transactions, however I've not been able to find the answer to (what I think) must be a common scenario.

I have a service that can be called to send emails. When it's called, it creates the email record in a table and then pushes the ID to ActiveMQ for processing. All good so far, however the queue picks the ID up and tries to send the email before the transaction is committed and the email is not the in database.

The service itself is transactional, but it may also be part of a a larger transaction.

What is the best way to handle this scenario? I'm using a Thread.sleep at the moment in the Consumer which works; however this feels dirty...

(I'm not using Spring)

StuPointerException
  • 7,117
  • 5
  • 29
  • 54
  • is this service an EJB and who is calling this service? – Madhusudana Reddy Sunnapu Feb 23 '16 at 15:32
  • It's a CDI service (ApplicationScoped) and will be called from any other CDI service. The Transactions are DeltaSpike (so unfortunately I can't use the `@Observes` TransactionPhase... feature of JavaEE). – StuPointerException Feb 23 '16 at 16:01
  • if you have support for XA, you may want to try with XADatasource and XAConnectionFactory.Or as TT suggested you can put the message in the queue from the class which is calling ur service after the call to service returns. – Madhusudana Reddy Sunnapu Feb 23 '16 at 16:12

2 Answers2

1

You can have a transaction that does the usual stuff plus inserts emails in a table. Don't send the mails in the transction.

Then afterward (the transaction succeeds) have a process clear the email table by forwarding to the queueing service.

TT.
  • 15,774
  • 6
  • 47
  • 88
  • I'm trying to avoid having a scheduled job, do you know of anywhere else I can hook into the transaction lifecycle to fire off this message (ideally it should be transparent from the caller)? I thought about using JPA events but they're inside the same transaction... – StuPointerException Feb 23 '16 at 13:39
  • @StuPointerException Send a message to a queue at the end of the transaction. Consumer would trigger on the message to send the mails. Wouldn't that work? The consumer process would not run in the transaction then. – TT. Feb 23 '16 at 14:25
  • Thanks for the assistance on this, the problem I'm having is knowing when the Tx has been committed, since it's already started when the service method is called. This is desirable since it means the email effectively gets rolled back if the calling method throws an exception. – StuPointerException Feb 23 '16 at 14:46
  • @StuPointerException Well you need control over the transaction if you want to handle this correctly. If you can't you need to figure out how to have strict control over the transaction, or fire the mailing in another layer. No way around that. – TT. Feb 23 '16 at 16:00
  • Thanks for the assistance! – StuPointerException Feb 24 '16 at 18:37
0

Maybe doing a flush right after persisting the mail would help ?

I'm actually curious to see how this could be fixed, since we have a similar problem in our application at work.

Kevyn Meganck
  • 609
  • 6
  • 15
  • Thanks for the suggestion, however I'm trying to avoid persisting the email record if the client throws an exception. I just can't seem to hook into the transaction lifecycle to know what becomes of said transaction! – StuPointerException Feb 23 '16 at 14:50