Este tema proporciona código de ejemplo en Java para enviar y consumir mensajes programados o diferidos mediante el SDK de cliente HTTP de ApsaraMQ for RocketMQ.
Diferencias entre mensajes programados y diferidos
Los mensajes programados y los mensajes diferidos son la misma función en la API. Ambos utilizan el método setStartDeliverTime para aplazar la entrega. La única diferencia radica en cómo se calcula la marca de tiempo:
|
Tipo |
Cómo establecer la hora de entrega |
Ejemplo |
|
Mensaje diferido |
Hora actual + desplazamiento |
|
|
Mensaje programado |
Marca de tiempo Unix absoluta en milisegundos |
|
El broker retiene cada mensaje hasta su hora de entrega especificada y luego lo libera para su consumo. Esta es una configuración por mensaje, por lo que cada uno puede tener su propia hora de entrega.
Para obtener más información, consulte Mensajes programados y mensajes diferidos.
Requisitos previos
Antes de empezar, asegúrese de cumplir con a continuación:
Creado una instancia, un topic y un grupo de consumidores en la consola de ApsaraMQ for RocketMQ
Creado un par de AccessKey para su cuenta de Alibaba Cloud
Cada topic admite solo un tipo de mensaje. No reutilice un topic configurado para mensajes normales si desea enviar mensajes programados o diferidos.
Envío de mensajes programados o diferidos
Todos los mensajes de este ejemplo usan setStartDeliverTime para aplazar la entrega durante 10 segundos. Para enviar un mensaje programado, reemplace el desplazamiento relativo con una marca de tiempo Unix absoluta en milisegundos (por ejemplo, 1654770600000 para 2022-06-09 18:30:00).
import com.aliyun.mq.http.MQClient;
import com.aliyun.mq.http.MQProducer;
import com.aliyun.mq.http.model.TopicMessage;
import java.util.Date;
public class Producer {
public static void main(String[] args) {
MQClient mqClient = new MQClient(
// HTTP endpoint. Find this on the Instance Details page, in the
// Endpoints tab under Basic Information.
"<your-http-endpoint>",
// Load credentials from environment variables to avoid hardcoding secrets.
System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"),
System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")
);
final String topic = "<your-topic>";
// If the instance has a namespace, specify the instance ID.
// If it does not have a namespace, set this to null or "".
final String instanceId = "<your-instance-id>";
MQProducer producer;
if (instanceId != null && instanceId != "") {
producer = mqClient.getProducer(instanceId, topic);
} else {
producer = mqClient.getProducer(topic);
}
try {
for (int i = 0; i < 4; i++) {
TopicMessage pubMsg = new TopicMessage(
"hello mq!".getBytes(), // Message body
"A" // Message tag
);
pubMsg.getProperties().put("a", String.valueOf(i)); // Custom property
pubMsg.setMessageKey("MessageKey");
// Defer delivery by 10 seconds.
// For a scheduled message, use an absolute timestamp instead,
// e.g., pubMsg.setStartDeliverTime(1654770600000L);
pubMsg.setStartDeliverTime(System.currentTimeMillis() + 10 * 1000);
TopicMessage pubResultMsg = producer.publishMessage(pubMsg);
System.out.println(new Date() + " Send mq message success."
+ " Topic is:" + topic
+ ", msgId is: " + pubResultMsg.getMessageId()
+ ", bodyMD5 is: " + pubResultMsg.getMessageBodyMD5());
}
} catch (Throwable e) {
System.out.println(new Date() + " Send mq message failed. Topic is:" + topic);
e.printStackTrace();
}
mqClient.close();
}
}
Reemplace a continuación marcadores de posición con sus valores reales:
|
Marcador de posición |
Descripción |
Dónde encontrarlo |
|
|
Endpoint HTTP |
Página Instance Details > pestaña Endpoints > HTTP Endpoint |
|
|
Nombre del topic |
Consola de ApsaraMQ for RocketMQ > Topics |
|
|
ID de instancia, o |
Página Instance Details > Basic Information |
Consumo de mensajes programados o diferidos
Consuma los mensajes programados y diferidos de la misma manera que los mensajes normales. El broker los retiene hasta la hora de entrega y luego los libera para su consumo.
El siguiente ejemplo utiliza sondeo largo (long polling) para consumir mensajes y enviar confirmaciones (ACK) al broker.
import com.aliyun.mq.http.MQClient;
import com.aliyun.mq.http.MQConsumer;
import com.aliyun.mq.http.common.AckMessageException;
import com.aliyun.mq.http.model.Message;
import java.util.ArrayList;
import java.util.List;
public class Consumer {
public static void main(String[] args) {
MQClient mqClient = new MQClient(
// HTTP endpoint. Find this on the Instance Details page, in the
// Endpoints tab under Basic Information.
"<your-http-endpoint>",
// The AccessKey ID for authentication.
"${ACCESS_KEY}",
// The AccessKey secret for authentication.
"${SECRET_KEY}"
);
final String topic = "<your-topic>";
final String groupId = "<your-group-id>";
// If the instance has a namespace, specify the instance ID.
// If it does not have a namespace, set this to null or "".
final String instanceId = "<your-instance-id>";
final MQConsumer consumer;
if (instanceId != null && instanceId != "") {
consumer = mqClient.getConsumer(instanceId, topic, groupId, null);
} else {
consumer = mqClient.getConsumer(topic, groupId);
}
// Consume messages in a loop. For production use, run multiple threads
// to consume messages concurrently.
do {
List<Message> messages = null;
try {
// Long polling: wait up to 3 seconds for new messages.
// - First parameter: max messages per batch (max: 16).
// - Second parameter: long polling timeout in seconds (max: 30).
messages = consumer.consumeMessage(3, 3);
} catch (Throwable e) {
e.printStackTrace();
try {
Thread.sleep(2000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
if (messages == null || messages.isEmpty()) {
System.out.println(Thread.currentThread().getName()
+ ": no new message, continue!");
continue;
}
// Process messages
for (Message message : messages) {
System.out.println("Receive message: " + message);
}
// ACK consumed messages. If the broker does not receive an ACK
// before the retry interval elapses, the message is redelivered.
{
List<String> handles = new ArrayList<String>();
for (Message message : messages) {
handles.add(message.getReceiptHandle());
}
try {
consumer.ackMessage(handles);
} catch (Throwable e) {
if (e instanceof AckMessageException) {
AckMessageException errors = (AckMessageException) e;
System.out.println("Ack message fail, requestId is:"
+ errors.getRequestId() + ", fail handles:");
if (errors.getErrorMessages() != null) {
for (String errorHandle : errors.getErrorMessages().keySet()) {
System.out.println("Handle:" + errorHandle
+ ", ErrorCode:" + errors.getErrorMessages().get(errorHandle).getErrorCode()
+ ", ErrorMsg:" + errors.getErrorMessages().get(errorHandle).getErrorMessage());
}
}
continue;
}
e.printStackTrace();
}
}
} while (true);
}
}
Reemplace a continuación marcadores de posición con sus valores reales:
|
Marcador de posición |
Descripción |
Dónde encontrarlo |
|
|
Endpoint HTTP |
Página Instance Details > pestaña Endpoints > HTTP Endpoint |
|
|
AccessKey ID para autenticación |
Consulte Crear un par de AccessKey |
|
|
AccessKey secret para autenticación |
Consulte Crear un par de AccessKey |
|
|
Nombre del topic |
Consola de ApsaraMQ for RocketMQ > Topics |
|
|
ID del grupo de consumidores |
Consola de ApsaraMQ for RocketMQ > Groups |
|
|
ID de instancia, o |
Página Instance Details > Basic Information |
Pasos siguientes
Mensajes programados y mensajes diferidos: Comprenda el ciclo de vida, las reglas de entrega y los límites de los mensajes programados y diferidos.
Envío y recepción de mensajes normales: Envíe mensajes que se entregan inmediatamente sin ningún retraso.