Use el SDK de cliente HTTP de Python para enviar y recibir mensajes programados y diferidos en ApsaraMQ for RocketMQ. Este tema proporciona ejemplos completos de código para productores y consumidores.
Funcionamiento de los mensajes programados y diferidos
Los mensajes programados y diferidos posponen su entrega a los consumidores hasta un momento específico:
Mensaje diferido: Se entrega después de un retraso fijo. Por ejemplo, un mensaje con un retraso de 10 segundos está disponible para los consumidores 10 segundos después de su envío.
Mensaje programado: Se entrega en un momento específico. Por ejemplo, un mensaje programado para 2024-01-15 15:00:00 se entrega exactamente a esa hora.
Mediante HTTP, ambos tipos usan la misma API. Establezca start_deliver_time con una marca de tiempo Unix futura en milisegundos:
Para un mensaje diferido, calcule la marca de tiempo como
current_time + delay_duration.Para un mensaje programado, establezca la marca de tiempo directamente en el momento de entrega deseado.
Para obtener más información, consulte Scheduled messages and delayed messages.
Requisitos previos
Antes de empezar, asegúrese de contar con lo siguiente:
El SDK de cliente HTTP de Python instalado. Para más detalles, consulte Prepare the environment
Una instancia, un tema y un grupo de consumidores de ApsaraMQ for RocketMQ creados en la consola de ApsaraMQ for RocketMQ. Para más detalles, consulte Create resources
Un par de AccessKey para su cuenta de Alibaba Cloud. Para más detalles, consulte Create an AccessKey pair
Envío de mensajes programados o diferidos
El siguiente ejemplo envía cuatro mensajes diferidos, cada uno entregado 10 segundos después de su envío. Para enviar un mensaje programado, establezca start_deliver_time con el momento de entrega deseado como una marca de tiempo Unix en milisegundos.
Reemplace los siguientes marcadores de posición con sus valores reales:
|
Marcador de posición |
Descripción |
Ejemplo |
|
|
Endpoint HTTP de su instancia. Encuéntrelo en la página Instance Details de la consola de ApsaraMQ for RocketMQ |
|
|
|
Nombre del tema al que se enviarán los mensajes |
|
|
|
ID de la instancia propietaria del tema. Obligatorio si la instancia tiene un namespace. Si la instancia no tiene namespace, pase una cadena vacía. Compruebe el estado del namespace en la página Instance Details |
|
import sys
import os
import time
from mq_http_sdk.mq_exception import MQExceptionBase
from mq_http_sdk.mq_producer import *
from mq_http_sdk.mq_client import *
# Initialize the producer client
mq_client = MQClient(
# HTTP endpoint. Find it in the HTTP Endpoint section
# of the Instance Details page in the ApsaraMQ for RocketMQ console.
"<http-endpoint>",
# AccessKey ID and AccessKey secret for authentication.
# Store credentials in environment variables instead of hardcoding them.
os.environ['ALIBABA_CLOUD_ACCESS_KEY_ID'],
os.environ['ALIBABA_CLOUD_ACCESS_KEY_SECRET']
)
topic_name = "<topic>"
instance_id = "<instance-id>"
producer = mq_client.get_producer(instance_id, topic_name)
# Send four messages
msg_count = 4
print("%sPublish Message To %s\nTopicName:%s\nMessageCount:%s\n" % (10 * "=", 10 * "=", topic_name, msg_count))
try:
for i in range(msg_count):
msg = TopicMessage(
"I am test message %s.hello" % i, # Message content
"tag1" # Message tag
)
# Set a custom message attribute
msg.put_property("a", "i")
# Set the message key for tracing
msg.set_message_key("MessageKey")
# Deliver this message after a 10-second delay.
# The value is a Unix timestamp in milliseconds.
# For a scheduled message, replace the calculation below
# with the target delivery time in milliseconds.
msg.set_start_deliver_time(int(round(time.time() * 1000)) + 10 * 1000)
re_msg = producer.publish_message(msg)
print("Publish Timer Message Succeed. MessageID:%s, BodyMD5:%s" % (re_msg.message_id, re_msg.message_body_md5))
except MQExceptionBase as e:
if e.type == "TopicNotExist":
print("Topic not exist, please create it.")
sys.exit(1)
print("Publish Message Fail. Exception:%s" % e)
**Parámetro clave: set_start_deliver_time**
Controla cuándo entrega el broker el mensaje. Pase una marca de tiempo Unix en milisegundos:
|
Tipo de entrega |
Cómo establecer la marca de tiempo |
Ejemplo |
|
Entrega diferida |
Hora actual más la duración del retraso |
|
|
Entrega programada |
Marca de tiempo absoluta del momento de entrega deseado |
|
Recepción de mensajes programados y diferidos
El broker retiene los mensajes programados y diferidos hasta que llega el momento de entrega y luego los pone a disposición para su consumo. Consúmalos de la misma manera que los mensajes normales.
El siguiente ejemplo usa sondeo largo para recibir y confirmar mensajes. Reemplace los siguientes marcadores de posición con sus valores reales:
|
Marcador de posición |
Descripción |
Ejemplo |
|
|
Endpoint HTTP de su instancia |
|
|
|
Nombre del tema del que se consumirán los mensajes |
|
|
|
ID del grupo de consumidores |
|
|
|
ID de la instancia. Pase una cadena vacía si la instancia no tiene namespace |
|
import os
import time
from mq_http_sdk.mq_exception import MQExceptionBase
from mq_http_sdk.mq_consumer import *
from mq_http_sdk.mq_client import *
# Initialize the consumer client
mq_client = MQClient(
"<http-endpoint>",
os.environ['ALIBABA_CLOUD_ACCESS_KEY_ID'],
os.environ['ALIBABA_CLOUD_ACCESS_KEY_SECRET']
)
topic_name = "<topic>"
group_id = "<group-id>"
instance_id = "<instance-id>"
consumer = mq_client.get_consumer(instance_id, topic_name, group_id)
# Long polling timeout in seconds (max: 30)
wait_seconds = 3
# Maximum messages per request (max: 16)
batch = 3
print(("%sConsume And Ak Message From Topic%s\nTopicName:%s\nMQConsumer:%s\nWaitSeconds:%s\n" \
% (10 * "=", 10 * "=", topic_name, group_id, wait_seconds)))
while True:
try:
# Long polling: the request blocks on the broker until a message
# arrives or wait_seconds elapses, whichever comes first.
recv_msgs = consumer.consume_message(batch, wait_seconds)
for msg in recv_msgs:
print(("Receive, MessageId: %s\nMessageBodyMD5: %s \
\nMessageTag: %s\nConsumedTimes: %s \
\nPublishTime: %s\nBody: %s \
\nNextConsumeTime: %s \
\nReceiptHandle: %s \
\nProperties: %s\n" % \
(msg.message_id, msg.message_body_md5,
msg.message_tag, msg.consumed_times,
msg.publish_time, msg.message_body,
msg.next_consume_time, msg.receipt_handle, msg.properties)))
except MQExceptionBase as e:
if e.type == "MessageNotExist":
print(("No new message! RequestId: %s" % e.req_id))
continue
print(("Consume Message Fail! Exception:%s\n" % e))
time.sleep(2)
continue
# Acknowledge consumed messages.
# If the broker does not receive an ACK before msg.next_consume_time,
# it redelivers the message. Each delivery generates a new receipt handle.
try:
receipt_handle_list = [msg.receipt_handle for msg in recv_msgs]
consumer.ack_message(receipt_handle_list)
print(("Ak %s Message Succeed.\n\n" % len(receipt_handle_list)))
except MQExceptionBase as e:
print(("\nAk Message Fail! Exception:%s" % e))
if e.sub_errors:
for sub_error in e.sub_errors:
print(("\tErrorHandle:%s,ErrorCode:%s,ErrorMsg:%s" % \
(sub_error["ReceiptHandle"], sub_error["ErrorCode"], sub_error["ErrorMessage"])))
Funcionamiento del sondeo largo
consume_message bloquea la solicitud en el broker durante un máximo de wait_seconds. Si un mensaje está disponible durante ese periodo, el broker responde de inmediato. De lo contrario, la solicitud finaliza al cumplirse el tiempo de espera.
|
Parámetro |
Descripción |
Rango |
|
|
Tiempo de espera del sondeo largo en segundos |
Máximo: 30 |
|
|
Número máximo de mensajes devueltos por solicitud |
Máximo: 16 |
Funcionamiento de la confirmación de mensajes
Después de procesar un mensaje, confírmelo al enviar el identificador de recibo de vuelta al broker. Si no llega ninguna confirmación antes de next_consume_time, el broker vuelve a entregar el mensaje con un nuevo identificador de recibo. Use siempre el identificador de la entrega más reciente.
Pasos siguientes
Scheduled messages and delayed messages -- conceptos y detalles de la función
Prepare the environment -- configuración del SDK para otros lenguajes