'IBM MQ does not roll back in WS-AT transaction
I have a similar problem to the case described in MQ Queue transaction not rolled back in a 2 phase transaction. I have a .NET client which does the following in one transaction:
- Writes one record to the first database.
- Puts one message into an IBM Websphere 8.0 MQ Series queue.
- Calls with WS-AT the web service as described in https://developers.redhat.com/quickstarts/eap/wsat-simple.
- Writes one record to the second database.
When the web service rolls back, the two databases roll back but not the IBM MQ Series queue. When one database fails, then the IBM MQ Series queue does roll back.
The method RestaurantTransactionPOC runs in a class that inherits from System.EnterpriseServices.ServicedComponent, that means, it runs under COM+.
Here is the code of RestaurantTransactionPOC:
Public Function RestaurantTransactionPOC(
uri As String, queueManager As String, queueName As String, textToWrite As String,
Optional failOnlRecvRep As Boolean = False,
Optional failGtsRecvRep As Boolean = False,
Optional failWSATService As Boolean = False,
Optional failMQSeries As Boolean = False) As String
Try
Dim result = ""
Dim msgId = GetMsgId()
Try
AddOnlRecvRep(msgId, failOnlRecvRep)
Catch ex As Exception
Debug.WriteLine(ex.ToString)
result &= ex.ToString & vbCrLf
End Try
Try
AddQueue(queueManager, queueName, msgId, failMQSeries)
Catch ex As Exception
Debug.WriteLine(ex.ToString)
result &= ex.ToString & vbCrLf
End Try
Try
ServicePointManager.SecurityProtocol = CType(SecurityProtocolType.Tls Or 768 Or 3072, SecurityProtocolType)
Dim client = CreateChannel(Of RestaurantServiceATChannel)(uri)
client.makeBooking()
Catch ex As Exception
Debug.WriteLine(ex.ToString)
result &= ex.ToString & vbCrLf
End Try
Try
AddGtsRecvRep(msgId, failGtsRecvRep)
Catch ex As Exception
Debug.WriteLine(ex.ToString)
result &= ex.ToString
End Try
ContextUtil.SetComplete()
Return result
Catch ex As Exception
ContextUtil.SetAbort()
Throw
End Try
End Function
Public Function CreateChannel(Of T)(uri As String) As T
binding = New CustomBinding(
New BindingElement() {
New TransactionFlowBindingElement(TransactionProtocol.WSAtomicTransaction11),
New TextMessageEncodingBindingElement() With {.MessageVersion = MessageVersion.Soap12},
New HttpsTransportBindingElement()})
binding.SendTimeout = New TimeSpan(0, 0, 30)
Dim endpoint As New EndpointAddress(uri)
Dim channelFactory = New ChannelFactory(Of T)(binding, endpoint)
Dim behavior = CType(channelFactory.Endpoint.Behaviors(1), ClientCredentials)
behavior.ClientCertificate.SetCertificate(
StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint,
"5f 82 82 e3 e9 20 fd ac 27 f5 cc 60 8a f5 8e 55 39 38 a0 30")
Return channelFactory.CreateChannel()
End Function
Why does the IBM MQ Series queue not roll back, when the WS-AT makeBooking service rolls back?
Solution 1:[1]
If I recall correctly, in some cases, MQ would not remove a message from a queue until a read attempt was made, at which time, if the message had not properly been committed, it would be backed out instead of delivered to the reader. Might want to take a look at those options on both the sending and receiving queue manager as well as for the queue and the reader.
Solution 2:[2]
Joe Zitzelberger is right. As soon as AddQueue is called (which calls IBM.WMQ.MQQueue.Put), the current depth (given by IBM.WMQ.MQQueue.CurrentDepth) is incremented by 1. But getting the message from the queue (by IBM.WMQ.MQQueue.Get) results in the MQRC_NO_MSG_AVAILABLE exception. By experimenting, I found out the behaviour is as follows depending on the different cases:
If ContextUtil.SetComplete is called, then
If the transaction is committed, then
CurrentDepth remains incremented.
The message is available for retrieval.
Else (transaction is aborted, because Db or WS-AT voted abort)
CurrentDepth remains incremented for 3 minutes, regardless of whether IBM.WMQ.MQQueue.Get is called in the meantime. Afther the 3 minutes, CurrentDepth returns to its original value (is decremented).
The message is not available for retrieval.
End If
Else (ContextUtil.SetAbort method is called)
(transaction is aborted)
CurrentDepth returns to original value (is decremented).
The message is not available for retrieval.
End If
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Joe Zitzelberger |
| Solution 2 | Alex |
