PHP / Magento Dev Blog

  • Publikacje
  • O autorze
  • Kontakt

Message Queue Framework with RabbitMQ – publisher, consumer, DDEV config

by Henryk Tews / Tuesday, 12 November 2019 / Published in Magento 2

Operations like sending emails, syncing with an ERP, or recalculating indexes do not have to block an HTTP request. Magento 2 has a built-in Message Queue Framework that lets you push such tasks to an asynchronous queue. I show how it works with RabbitMQ and how to write your own publisher and consumer.

What is the Message Queue Framework in Magento 2?

MQF is an abstraction layer over message brokers. Magento supports two backends:

  • MySQL – the default, zero configuration, sufficient for smaller deployments
  • RabbitMQ – recommended for production environments, supports routing, retry, dead letter queues

Architecture: Publisher (sends message), Queue (stores it), Consumer (processes it).

Module configuration – XML files

Define the message topic in etc/communication.xml:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Communication/etc/communication.xsd">
    <topic name="vendor.module.order.export"
           request="Vendor\Module\Api\Data\OrderExportRequestInterface"/>
</config>

Queue and binding configuration in etc/queue_topology.xml:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/topology.xsd">
    <exchange name="magento" type="topic" connection="amqp">
        <binding id="orderExportBinding"
                 topic="vendor.module.order.export"
                 destinationType="queue"
                 destination="vendor.order.export"/>
    </exchange>
</config>

Register the consumer in etc/queue_consumer.xml:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/consumer.xsd">
    <consumer name="vendor.order.export.consumer"
              queue="vendor.order.export"
              connection="amqp"
              handler="Vendor\Module\Model\Consumer\OrderExportConsumer::process"
              maxMessages="100"/>
</config>

Publisher – sending messages to the queue

<?php

namespace Vendor\Module\Model;

use Magento\Framework\MessageQueue\PublisherInterface;
use Vendor\Module\Api\Data\OrderExportRequestInterfaceFactory;

class OrderExportPublisher
{
    private const TOPIC = 'vendor.module.order.export';

    public function __construct(
        private PublisherInterface $publisher,
        private OrderExportRequestInterfaceFactory $requestFactory
    ) {}

    public function publish(int $orderId): void
    {
        $request = $this->requestFactory->create();
        $request->setOrderId($orderId);

        // Message goes into the queue - HTTP request ends immediately
        $this->publisher->publish(self::TOPIC, $request);
    }
}

Consumer – processing messages

<?php

namespace Vendor\Module\Model\Consumer;

use Vendor\Module\Api\Data\OrderExportRequestInterface;

class OrderExportConsumer
{
    public function __construct(
        private \Psr\Log\LoggerInterface $logger,
        private \Vendor\Module\Model\ErpExporter $erpExporter
    ) {}

    public function process(OrderExportRequestInterface $request): void
    {
        $orderId = $request->getOrderId();

        try {
            $this->erpExporter->export($orderId);
            $this->logger->info('Order exported successfully', ['order_id' => $orderId]);
        } catch (\Exception $e) {
            // Exception = message goes to dead letter queue (with RabbitMQ)
            $this->logger->error('Export failed', [
                'order_id' => $orderId,
                'error'    => $e->getMessage(),
            ]);
            throw $e; // pass on - Magento handles retry
        }
    }
}

Starting the consumer

# Start manually (for testing)
bin/magento queue:consumers:start vendor.order.export.consumer

# With message limit
bin/magento queue:consumers:start vendor.order.export.consumer --max-messages=500

# On production - via supervisor
# [program:magento_order_export]
# command=/var/www/magento/bin/magento queue:consumers:start vendor.order.export.consumer
# autostart=true
# autorestart=true

RabbitMQ in DDEV

# .ddev/docker-compose.rabbitmq.yaml
version: '3.6'
services:
  rabbitmq:
    image: rabbitmq:3.8-management
    environment:
      RABBITMQ_DEFAULT_USER: magento
      RABBITMQ_DEFAULT_PASS: magento
    ports:
      - "5672"
      - "15672:15672" # management panel
    labels:
      com.ddev.site-name: ${DDEV_SITENAME}

The RabbitMQ management panel is available at http://localhost:15672 – you can monitor queues, message counts and dead letter messages there.

Summary

The Message Queue Framework in Magento 2 lets you move time-consuming operations outside the request-response cycle. The XML configuration looks verbose but follows a repeatable pattern. RabbitMQ with retry and dead letter queues is the right choice for production environments handling large order volumes.

About Henryk Tews

What you can read next

Xdebug – configuration, PHPStorm, debugging Magento plugins
Strategy pattern in PHP – and how Magento 2 uses it in pricing

© 2026 Created by

TOP
Zarządzaj zgodą
Aby zapewnić jak najlepsze wrażenia, korzystamy z technologii, takich jak pliki cookie, do przechowywania i/lub uzyskiwania dostępu do informacji o urządzeniu. Zgoda na te technologie pozwoli nam przetwarzać dane, takie jak zachowanie podczas przeglądania lub unikalne identyfikatory na tej stronie. Brak wyrażenia zgody lub wycofanie zgody może niekorzystnie wpłynąć na niektóre cechy i funkcje.
Funkcjonalne Always active
Przechowywanie lub dostęp do danych technicznych jest ściśle konieczny do uzasadnionego celu umożliwienia korzystania z konkretnej usługi wyraźnie żądanej przez subskrybenta lub użytkownika, lub wyłącznie w celu przeprowadzenia transmisji komunikatu przez sieć łączności elektronicznej.
Preferencje
Przechowywanie lub dostęp techniczny jest niezbędny do uzasadnionego celu przechowywania preferencji, o które nie prosi subskrybent lub użytkownik.
Statystyka
Przechowywanie techniczne lub dostęp, który jest używany wyłącznie do celów statystycznych. Przechowywanie techniczne lub dostęp, który jest używany wyłącznie do anonimowych celów statystycznych. Bez wezwania do sądu, dobrowolnego podporządkowania się dostawcy usług internetowych lub dodatkowych zapisów od strony trzeciej, informacje przechowywane lub pobierane wyłącznie w tym celu zwykle nie mogą być wykorzystywane do identyfikacji użytkownika.
Marketing
Przechowywanie lub dostęp techniczny jest wymagany do tworzenia profili użytkowników w celu wysyłania reklam lub śledzenia użytkownika na stronie internetowej lub na kilku stronach internetowych w podobnych celach marketingowych.
  • Manage options
  • Manage services
  • Manage {vendor_count} vendors
  • Read more about these purposes
Zobacz preferencje
  • {title}
  • {title}
  • {title}