Tüm Ürünler
Search
Belge Merkezi

ApsaraMQ for RocketMQ:Send and consume scheduled and delayed messages by using the PHP HTTP SDK

Son Güncelleme:Oct 04, 2026

Aşağıdaki PHP kod örnekleri, ApsaraMQ for RocketMQ HTTP istemci SDK'sı ile zamanlanmış ve gecikmeli mesajların nasıl gönderileceğini ve tüketileceğini gösterir.

Zamanlanmış ve gecikmeli mesajların çalışma mantığı

Zamanlanmış ve gecikmeli mesajlar, yayınlandıktan hemen sonra ulaşmak yerine teslimatı erteler.

  • Gecikmeli mesaj: Belirtilen bir gecikme süresinin ardından teslim edilir. Örnek: Gönderildikten 30 saniye sonra teslim edin.

  • Zamanlanmış mesaj: Belirli bir zamanda teslim edilir. Örnek: 2024-06-15 09:00:00 tarihinde teslim edin.

Her iki tür de aynı API'yi kullanır. Aracının (broker) mesajı ne zaman teslim etmesi gerektiğini temsil eden milisaniye düzeyinde bir Unix zaman damgasıyla setStartDeliverTime yöntemini çağırın.

  • Bir gecikmeli mesaj için zaman damgasını geçerli saat + gecikme süresi olarak hesaplayın.

  • Bir zamanlanmış mesaj için hedef teslim saatini doğrudan milisaniye düzeyinde bir Unix zaman damgasına dönüştürün.

Yaygın kullanım senaryoları:

  • Sipariş zaman aşımı: Sipariş oluşturulduğunda gecikmeli bir mesaj yayınlayarak ödenmemiş bir siparişi 30 dakika sonra iptal edin.

  • Geri çekilmeli yeniden deneme: Başarısız olan bir görevi hemen yeniden denemek yerine bir gecikmeyle tekrar işleyin.

  • Zamanlı bildirimler: Planlanmış bir etkinlikten 15 dakika önce gibi belirli bir zamanda hatırlatıcı tetikleyin.

Daha fazla bilgi için bkz. Zamanlanmış mesajlar ve gecikmeli mesajlar.

Ön koşullar

Başlamadan önce aşağıdakileri yaptığınızdan emin olun:

Zamanlanmış veya gecikmeli mesajlar gönderme

Aşağıdaki kod, her biri yayınlamadan 10 saniye sonra teslim edilen dört gecikmeli mesaj gönderir. Bunun yerine zamanlanmış bir mesaj göndermek için hedef teslim saatini milisaniye düzeyinde bir Unix zaman damgası olarak setStartDeliverTime yöntemine iletin.

Kodu çalıştırmadan önce yer tutucuları değiştirin:

Yer Tutucu Açıklama Örnek
<HTTP_ENDPOINT> ApsaraMQ for RocketMQ konsolundaki Instance Details sayfasından alınan HTTP uç noktası http://xxxx.mq-http.cn-hangzhou.aliyuncs.com
<TOPIC> Konsolda oluşturulan konu adı scheduled-msg-topic
<INSTANCE_ID> Örnek kimliği. Örneğin ad alanı yoksa null veya "" olarak ayarlayın MQ_INST_xxxx
<?php

require "vendor/autoload.php";

use MQ\Model\TopicMessage;
use MQ\MQClient;

class ProducerTest
{
    private $client;
    private $producer;

    public function __construct()
    {
        $this->client = new MQClient(
            // HTTP endpoint from the Instance Details page in the ApsaraMQ for RocketMQ console
            "<HTTP_ENDPOINT>",
            // AccessKey ID for authentication
            getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"),
            // AccessKey secret for authentication
            getenv('ALIBABA_CLOUD_ACCESS_KEY_SECRET')
        );

        $topic = "<TOPIC>";
        // Instance ID. If the instance has no namespace, set to null or "".
        $instanceId = "<INSTANCE_ID>";

        $this->producer = $this->client->getProducer($instanceId, $topic);
    }

    public function run()
    {
        try
        {
            for ($i = 1; $i <= 4; $i++)
            {
                $publishMessage = new TopicMessage(
                    "hello mq! " // Message body
                );
                // Custom message property
                $publishMessage->putProperty("a", $i);
                // Message key for tracing
                $publishMessage->setMessageKey("MessageKey");

                // Deliver the message 10 seconds from now.
                // For a scheduled message, set this to the target delivery time
                // as a millisecond-level Unix timestamp.
                $publishMessage->setStartDeliverTime(time() * 1000 + 10 * 1000);

                $result = $this->producer->publishMessage($publishMessage);

                print "Send mq message success. msgId is:" . $result->getMessageId()
                    . ", bodyMD5 is:" . $result->getMessageBodyMD5() . "\n";
            }
        } catch (\Exception $e) {
            print_r($e->getMessage() . "\n");
        }
    }
}

$instance = new ProducerTest();
$instance->run();

?>

Önemli noktalar:

  • setStartDeliverTime yöntemi milisaniye düzeyinde bir Unix zaman damgası kabul eder. PHP'de time() saniye döndürür, bu nedenle dönüştürmek için 1000 ile çarpın.

  • 10 saniyelik bir gecikme için: time() * 1000 + 10 * 1000.

  • Belirli bir zamanda teslim etmek için o saati milisaniye cinsinden bir Unix zaman damgasına dönüştürün. Örneğin, 2024-06-15 09:00:00 UTC tarihinde teslim etmek için: strtotime('2024-06-15 09:00:00') * 1000.

Zamanlanmış veya gecikmeli mesajları tüketme

Zamanlanmış ve gecikmeli mesajlar, normal mesajlarla aynı şekilde tüketilir. Teslimat zamanı geldiğinde mesajlar uzun polling yoluyla kullanılabilir hale gelir.

Kodu çalıştırmadan önce yer tutucuları değiştirin:

Yer Tutucu Açıklama Örnek
<HTTP_ENDPOINT> Instance Details sayfasından alınan HTTP uç noktası http://xxxx.mq-http.cn-hangzhou.aliyuncs.com
<TOPIC> Konsolda oluşturulan konu adı scheduled-msg-topic
<GROUP_ID> Konsolda oluşturulan tüketici grubu kimliği GID_scheduled_consumer
<INSTANCE_ID> Örnek kimliği. Örneğin ad alanı yoksa null veya "" olarak ayarlayın MQ_INST_xxxx
<?php

use MQ\MQClient;

require "vendor/autoload.php";

class ConsumerTest
{
    private $client;
    private $consumer;

    public function __construct()
    {
        $this->client = new MQClient(
            // HTTP endpoint from the Instance Details page in the ApsaraMQ for RocketMQ console
            "<HTTP_ENDPOINT>",
            // AccessKey ID for authentication
            getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"),
            // AccessKey secret for authentication
            getenv('ALIBABA_CLOUD_ACCESS_KEY_SECRET')
        );

        $topic = "<TOPIC>";
        // Consumer group ID created in the ApsaraMQ for RocketMQ console
        $groupId = "<GROUP_ID>";
        // Instance ID. If the instance has no namespace, set to null or "".
        $instanceId = "<INSTANCE_ID>";

        $this->consumer = $this->client->getConsumer($instanceId, $topic, $groupId);
    }

    public function ackMessages($receiptHandles)
    {
        try {
            $this->consumer->ackMessage($receiptHandles);
        } catch (\Exception $e) {
            if ($e instanceof MQ\Exception\AckMessageException) {
                // ACK may fail if the receipt handle has expired
                printf("Ack Error, RequestId:%s\n", $e->getRequestId());
                foreach ($e->getAckMessageErrorItems() as $errorItem) {
                    printf("\tReceiptHandle:%s, ErrorCode:%s, ErrorMsg:%s\n",
                        $errorItem->getReceiptHandle(),
                        $errorItem->getErrorCode(),
                        $errorItem->getErrorMessage());
                }
            }
        }
    }

    public function run()
    {
        // Consume messages in a loop. For production use, run multiple threads
        // to consume messages concurrently.
        while (True) {
            try {
                // Long polling: if no message is available, the request waits
                // on the broker until a message arrives or the polling period ends.
                $messages = $this->consumer->consumeMessage(
                    3, // Max messages per request (up to 16)
                    3  // Long polling timeout in seconds (up to 30)
                );
            } catch (\MQ\Exception\MessageResolveException $e) {
                // Thrown when some messages contain invalid characters and cannot be parsed
                $messages = $e->getPartialResult()->getMessages();
                $failMessages = $e->getPartialResult()->getFailResolveMessages();

                $receiptHandles = array();
                foreach ($messages as $message) {
                    $receiptHandles[] = $message->getReceiptHandle();
                    printf("MsgID %s\n", $message->getMessageId());
                }
                foreach ($failMessages as $failMessage) {
                    $receiptHandles[] = $failMessage->getReceiptHandle();
                    printf("Fail To Resolve Message. MsgID %s\n", $failMessage->getMessageId());
                }
                $this->ackMessages($receiptHandles);
                continue;
            } catch (\Exception $e) {
                if ($e instanceof MQ\Exception\MessageNotExistException) {
                    // No messages available. Long polling continues on the next iteration.
                    printf("No message, continue long polling! RequestId:%s\n", $e->getRequestId());
                    continue;
                }

                print_r($e->getMessage() . "\n");

                sleep(3);
                continue;
            }

            print "consume finish, messages:\n";

            $receiptHandles = array();
            foreach ($messages as $message) {
                $receiptHandles[] = $message->getReceiptHandle();

                printf("MessageID:%s TAG:%s BODY:%s \nPublishTime:%d, FirstConsumeTime:%d, \nConsumedTimes:%d, NextConsumeTime:%d, MessageKey:%s\n",
                    $message->getMessageId(), $message->getMessageTag(), $message->getMessageBody(),
                    $message->getPublishTime(), $message->getFirstConsumeTime(),
                    $message->getConsumedTimes(), $message->getNextConsumeTime(),
                    $message->getMessageKey());
                print_r($message->getProperties());
            }

            // If the broker does not receive an ACK before the time specified
            // in getNextConsumeTime(), the message is redelivered.
            // Each delivery generates a new receipt handle.
            print_r($receiptHandles);
            $this->ackMessages($receiptHandles);
            print "ack finish\n";
        }

    }
}

$instance = new ConsumerTest();
$instance->run();

?>

Mesaj tüketimi hakkında bilinmesi gerekenler

  • Uzun polling: Kullanılabilir bir mesaj olmadığında, aracı (broker) bir mesaj gelene kadar veya polling zaman aşımı dolana kadar tüketicinin isteğini bekletir. Bu, gereksiz ağ isteklerini azaltır.

  • ACK (tüketim onayı): Tüketici bir mesajı işledikten sonra makbuz tanıtıcısı (receipt handle) ile birlikte bir ACK gönderir. Aracı, getNextConsumeTime() öncesinde ACK almazsa mesajı yeniden teslim eder.

  • Makbuz tanıtıcısının sona ermesi: Her teslimat, kendi sona erme süresine sahip benzersiz bir makbuz tanıtıcısı atar. Süresi dolmuş bir tanıtıcı, ACK işleminin başarısız olmasına ve yeniden teslimata neden olur.

  • Ayrıştırma hataları: Bir mesaj gövdesi geçersiz karakterler içeriyorsa SDK MessageResolveException özel durumu oluşturur. Başarıyla ayrıştırılan mesajları almak ve hataları ayrı olarak işlemek için getPartialResult() yöntemini çağırın.

İlgili belgeler