This topic introduces the concepts, scenarios, and usage precautions of RocketMQ transactional messages.
- Transactional messages: RocketMQ provides the distributed transaction function like X/Open XA to ensure transaction consistency.
- Half message: A message that temporarily cannot be delivered. When a message is successfully sent to the RocketMQ broker, but the broker does not receive the second acknowledgment of the message from the producer, then the message is marked as “temporarily undeliverable”. The message in this status is called a half message.
- Message status check: Network disconnection or producer application restart may result in the loss of the second acknowledgment for a transactional message. When the RocketMQ broker finds that a message remains as a half message for a long time, it will send a request to the message producer to check the final status of the message (Commit or Rollback).
Transactional messages can be applied in the following scenarios:
In the process of placing an order through the shopping cart, the user entry is the shopping cart system, and the transaction order entry is the transaction system. The data between the two systems must eventually become consistent. In this case, transactional messages can be used for processing. After placing an order, the transaction system sends a transaction order message to RocketMQ. The shopping cart system subscribes to the transaction order message of RocketMQ, performs corresponding business processing, and updates the shopping cart data.
The interaction process of RocketMQ transactional messages is shown below:
In the preceding figure:
- A sender sends a message to the RocketMQ broker.
- The RocketMQ broker sets the message to be persistent, and returns an ACK message to the sender. At this time, the message is a half message.
- The sender starts to execute the local transaction logic.
- Based on the transaction execution result, the sender submits a secondary ACK message (Commit or Rollback) to the RocketMQ broker. If the message state is Commit, the RocketMQ broker marks the message as deliverable, and the consumer will receive this message. If it is Rollback, the RocketMQ broker deletes the half message, and the consumer will not receive this message.
- In the case of network disconnection or application restart, the secondary ACK message submitted in step 4 will not reach the RocketMQ broker. After a certain period of time, the RocketMQ broker initiates a message status check request.
- Upon receiving the status check request, the sender checks the final local transaction execution result.
- Based on the final status of the local transaction, the sender submits a secondary ACK message again, and the RocketMQ broker follows step 4 to process the half message.
Note: The transactional message sending involves step 1, step 2, step 3, and step 4, while the transactional message status check involves step 5, step 6, and step 7.
Producer IDs of transactional messages cannot be shared with producer IDs of other types of messages. Unlike other types of messages, transactional messages allow backward queries. The RocketMQ broker can query data on clients by producer ID.
You must specify the implementation class of LocalTransactionChecker when creating the producer of a transactional message through ONSFactory.createTransactionProducer, so that message status check can be performed when exceptions occur.
When the transactional message is sent to execute the local transaction, any of the following three statuses may be returned in the execute method:
- TransactionStatus.CommitTransaction: The transaction is submitted, and the consumer can consume the message.
- TransactionStatus.RollbackTransaction: The transaction is rolled back, and the message is discarded and cannot be consumed.
- TransactionStatus.Unknow: The status cannot be determined, and the RocketMQ broker is expected to send a request to the sender to check message status after a fixed period of time.
You can set the shortest time for the first message status check for each message as follows:
```javaMessage message = new Message(); //Add the shortest time (unit: s) for the first message status check in the message attribute. For the following setting, the first status check is done in 120~125 seconds: message.putUserProperties(PropertyKeyConst.CheckImmunityTimeInSeconds,”120”);
//The method above determines only the shortest time for the first message status check, and the actual time to perform the check usually floats backward 0~5 seconds. If the transaction is not submitted after the first message status check, then the status check will be performed every 5 seconds.```
Sample code for sending transactional messages can be found in the following documentation: