Use the Simple Message Queue (SMQ, formerly MNS) SDK for Java to pull messages from a queue, process them, and delete them after successful consumption.
Prerequisites
Before you begin, ensure that you have:
Installed the SMQ SDK for Java. See Install SDK for Java
Configured an endpoint and access credentials. See Configure endpoints and access credentials
Authorization information
By default, only an Alibaba Cloud account can call this operation. To call it as a Resource Access Management (RAM) user, grant the user the required permissions first.
|
Name |
Value |
|
API |
ReceiveMessage |
|
Action |
mns:ReceiveMessage |
|
Resource |
acs:mns:$region:$accountid:/queues/$queueName/messages |
How message receiving works
When a consumer calls ReceiveMessage , the message moves from Active to Inactive state for the duration set by the VisibilityTimeout parameter.
Delete the message within the visibility timeout by calling DeleteMessage. If you do not delete the message in time, it returns to Active state and becomes available for consumption again.
Message body encoding
Base64 encoding is disabled by default. The msgBodyBase64Switch property in your configuration file defaults to false. If your message body contains no special characters, use the raw string methods:
Send: call
message.setMessageBodyAsRawString.Receive: call
message.getMessageBodyAsRawString.
Receive methods
The SDK provides two ways to receive messages. Use long polling batch receive in production for higher throughput and fewer API calls.
|
Method |
API call |
When to use |
|
Single receive |
|
Low-throughput scenarios or quick testing. |
|
Long polling batch receive (recommended) |
|
Production workloads. Receives up to |
Long polling keeps the connection open for the duration specified by waitSeconds and returns messages as soon as they are available, rather than returning an empty response immediately. This reduces empty responses and API calls compared to short polling.
Sample code
For the complete runnable source, see ReceiveMessageDemo on GitHub.
Configuration
Create or update ${"user.home"}/.aliyun-mns.properties with your endpoint and Base64 encoding preference:
mns.endpoint=http://xxxxxxx
mns.msgBodyBase64Switch=true/false
Store your AccessKey ID and AccessKey secret as environment variables following Alibaba Cloud security best practices.
Code
The sample loops continuously, alternating between a single receive and a long polling batch receive. Each received message is printed and then deleted.
package com.aliyun.mns.sample.queue;
import com.aliyun.mns.client.CloudAccount;
import com.aliyun.mns.client.CloudQueue;
import com.aliyun.mns.client.MNSClient;
import com.aliyun.mns.common.ClientException;
import com.aliyun.mns.common.ServiceException;
import com.aliyun.mns.common.ServiceHandlingRequiredException;
import com.aliyun.mns.common.utils.ServiceSettings;
import com.aliyun.mns.model.Message;
import java.util.List;
/**
* Prerequisites:
* 1. Set the AccessKey ID and AccessKey secret as environment variables following Alibaba Cloud security best practices.
* 2. Create ${"user.home"}/.aliyun-mns.properties with the following content:
* mns.endpoint=http://xxxxxxx
* mns.msgBodyBase64Switch=true/false
*/
public class ReceiveMessageDemo {
/**
* Whether to decode the message body from Base64.
*/
private static final Boolean IS_BASE64 = Boolean.valueOf(ServiceSettings.getMNSPropertyValue("msgBodyBase64Switch","false"));
public static void main(String[] args) {
String queueName = "cloud-queue-demo";
// Set the AccessKey ID and AccessKey secret as environment variables following Alibaba Cloud security best practices.
CloudAccount account = new CloudAccount(ServiceSettings.getMNSAccountEndpoint());
// Initialize the client once and reuse it.
MNSClient client = account.getMNSClient();
CloudQueue queue = client.getQueueRef(queueName);
// Receive and process messages in a loop.
loopReceive(queue, client);
// Close the client after processing.
client.close();
}
private static void loopReceive(CloudQueue queue, MNSClient client) {
while (true) {
try {
// Single receive: basic method.
singleReceive(queue);
// Long polling batch receive: recommended for production.
longPollingBatchReceive(queue);
} catch (ClientException ce) {
System.out.println("Network connection error between client and SMQ service. "
+ "Check your network and DNS settings.");
// Retry on transient network errors.
} catch (ServiceException se) {
if (se.getErrorCode().equals("QueueNotExist")) {
System.out.println("Queue does not exist. Create the queue before calling ReceiveMessage.");
client.close();
return;
} else if (se.getErrorCode().equals("TimeExpired")) {
System.out.println("Request expired. Check your local machine clock for time synchronization issues.");
return;
}
// Retry on transient service errors.
} catch (Exception e) {
System.out.println("Unexpected error: " + e.getMessage());
}
}
}
private static void longPollingBatchReceive(CloudQueue queue) throws ServiceHandlingRequiredException {
System.out.println("=============start longPollingBatchReceive=============");
// Maximum number of messages to receive per call.
int batchSize = 15;
// Long polling wait time in seconds.
int waitSeconds = 15;
List<Message> messages = queue.batchPopMessage(batchSize, waitSeconds);
if (messages != null && messages.size() > 0) {
for (Message message : messages) {
printMsgAndDelete(queue,message);
}
}
System.out.println("=============end longPollingBatchReceive=============");
}
private static void singleReceive(CloudQueue queue) throws ServiceHandlingRequiredException {
System.out.println("=============start singleReceive=============");
Message popMsg = queue.popMessage();
printMsgAndDelete(queue, popMsg);
System.out.println("=============end singleReceive=============");
}
private static void printMsgAndDelete(CloudQueue queue, Message popMsg) throws ServiceHandlingRequiredException {
if (popMsg != null) {
System.out.println("message handle: " + popMsg.getReceiptHandle());
System.out.println("message body: " + (IS_BASE64 ? popMsg.getMessageBody() : popMsg.getMessageBodyAsRawString()));
System.out.println("message id: " + popMsg.getMessageId());
System.out.println("message dequeue count:" + popMsg.getDequeueCount());
// Add your message processing logic here.
// Delete the message after successful consumption.
queue.deleteMessage(popMsg.getReceiptHandle());
System.out.println("delete message successfully.\n");
}
}
}
Error handling
The loop catches three exception types. Handle each as follows:
|
Exception type |
Cause |
Recovery action |
|
|
Network connection issues between the client and the SMQ service |
Retry. Check your network and DNS settings. |
|
|
The specified queue does not exist |
Create the queue before calling ReceiveMessage. |
|
|
The request has expired |
Check your local machine clock for time synchronization issues. |
|
Generic |
Unknown errors |
Retry. Log the error for further investigation. |
Expected output
A successful run produces output similar to the following. Each block shows the receipt handle, message body, message ID, and dequeue count before confirming deletion.
=============start singleReceive=============
message handle: 1-ODU4OTkzNDU5My0xNDMyNzI3ODI3LTItOA==
message body: This is a test message
message id: 5F290C926D472878-2-14D9529A8FA-20000****
message dequeue count:1
delete message successfully.
=============end singleReceive=============
=============start longPollingBatchReceive=============
message handle: 1-ODU4OTkzNDU5My0xNDMyNzI3MzI3LTItOA==
message body: Batch message 1
message id: 5F290C926D472878-2-14D9529A8FA-20001****
message dequeue count:1
delete message successfully.
message handle: 1-ODU4OTkzNDU5My0xNDMyNzI3NDI3LTItOA==
message body: Batch message 2
message id: 5F290C926D472878-2-14D9529A8FA-20002****
message dequeue count:1
delete message successfully.
=============end longPollingBatchReceive=============