Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using transactions with JMS (ActiveMQ)

In our backend there are several services that send and receive messages via JMS with Apache ActiveMQ. Each service has a single session to the ActiveMQ broker. We now want to do the following (pseudo code):

Service s1:

Message m = createMessage("s2","Hello World")
sendMessage(m)
try {
   Message answer = commit()
   ...
} catch (TransactionFailedException e){
   ...
}

Service s2:

onMessageReceive:
try {
   Message m = getReceivedMessage()
   Message answer = doSomeStuff()
   send(answer)
} (Exception e) {
   rollback()
}

The commit obviuosly has to block until the answer arrives or the transaction failes. It should also be possible that service s2 creates a new nested transaction because s2 is sending a message to another service. How can transactions from ActiveMQ be used to achieve this behaviour? There are some examples available but in these examples transactions are merely used as a batch mechanism to send messages.

like image 684
problemzebra Avatar asked Nov 05 '22 05:11

problemzebra


1 Answers

I'm interpreting you question to mean that you want a failure of work in s2 to cause an ongoing transaction in s1 to be rolled back.

So you want

s1 do some work

s2 do some work

if ( s2 OK )
   perhaps do even more work in s1
   commit s1
else
   rollback s1

The asynchronous model of JMS is not classically designed for this purpose. The fundamental reason is because

  1. During a transaction resources (eg database records) are locked - s1 has done some work, until the transaction has resolved those resources must be kept locked.
  2. Asynch processing is designed to decouple s2 work from s1 work, s2 work might happen many minutes or indeed days after the request was placed on the queue. S2 can't know whether or not s1 is still waiting for him. The whole design point of JMS is to decouple processing in s1 and s2.

There are two approaches to achieving coordination between s1 and s2:

One is to use true distributed transactions, using a protocol other than JMS, for example EJBs can propagate transactions from one process to another, or use WS-AtomicTransaction and web Services. This does add operational complexity - you have to manange transaction logs and scenarios where you have a long-term failure of one component.

The alternative is to design the two cooperating systems to robustly handle "compensating" work. You accept that, for example s2 may fail, and have secondary processing to deal with resending requests, dealing with timeouts etc. In the end you may come down to some situations where humans need to be involved, but with good design these situations can be minimal. In large scale systems there's often no alternative to this, for example an airline's booking system and a hotel chain's booking system may well not be designed for distributed transaction coordination so there's no alternative to having some careful processing to manage reserving flights and rooms.

like image 65
djna Avatar answered Nov 10 '22 14:11

djna