Este tópico fornece exemplos de código Java para enviar e consumir mensagens agendadas ou atrasadas usando o SDK de cliente HTTP do ApsaraMQ for RocketMQ.
Mensagens agendadas versus atrasadas
No nível da API, mensagens agendadas e atrasadas são o mesmo recurso. Ambas usam o método setStartDeliverTime para adiar a entrega. A única diferença reside no cálculo do timestamp:
|
Tipo |
Como definir o horário de entrega |
Exemplo |
|
Mensagem atrasada |
Hora atual + deslocamento |
|
|
Mensagem agendada |
Timestamp Unix absoluto em milissegundos |
|
O broker retém cada mensagem até o horário de entrega especificado e depois a libera para consumo. Essa configuração é por mensagem, portanto cada uma pode ter seu próprio horário de entrega.
Para mais informações, consulte Mensagens agendadas e mensagens atrasadas.
Pré-requisitos
Antes de começar, verifique se você já:
Criou uma instância, um tópico e um grupo de consumidores no console do ApsaraMQ for RocketMQ
Criou um par de AccessKey para sua conta Alibaba Cloud
Cada tópico aceita apenas um tipo de mensagem. Não reutilize um tópico configurado para mensagens normais no envio de mensagens agendadas ou atrasadas.
Enviar mensagens agendadas ou atrasadas
Neste exemplo, todas as mensagens usam setStartDeliverTime para adiar a entrega em 10 segundos. Para enviar uma mensagem agendada, substitua o deslocamento relativo por um timestamp Unix absoluto em milissegundos (por exemplo, 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();
}
}
Substitua os espaços reservados abaixo pelos valores reais:
|
Espaço reservado |
Descrição |
Onde encontrar |
|
|
Endpoint HTTP |
Página Instance Details > aba Endpoints > HTTP Endpoint |
|
|
Nome do tópico |
Console do ApsaraMQ for RocketMQ > Topics |
|
|
ID da instância ou |
Página Instance Details > Basic Information |
Consumir mensagens agendadas ou atrasadas
Consuma mensagens agendadas e atrasadas da mesma forma que as mensagens normais. O broker as retém até o horário de entrega e depois as libera para consumo.
O exemplo a seguir usa long polling para consumir mensagens e enviar confirmações (ACKs) ao 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);
}
}
Preencha os espaços reservados abaixo com os valores correspondentes:
|
Espaço reservado |
Descrição |
Onde encontrar |
|
|
Endpoint HTTP |
Página Instance Details > aba Endpoints > HTTP Endpoint |
|
|
AccessKey ID para autenticação |
Consulte Criar um par de AccessKey |
|
|
AccessKey secret para autenticação |
Consulte Criar um par de AccessKey |
|
|
Nome do tópico |
Console do ApsaraMQ for RocketMQ > Topics |
|
|
ID do grupo de consumidores |
Console do ApsaraMQ for RocketMQ > Groups |
|
|
ID da instância ou |
Página Instance Details > Basic Information |
Próximos passos
Mensagens agendadas e mensagens atrasadas: Entenda o ciclo de vida, as regras de entrega e os limites dessas mensagens.
Enviar e receber mensagens normais: Envie mensagens entregues imediatamente, sem atraso.