RabbitMQ in Magento 2 — async processing voor grote shops
Terug naar blog

RabbitMQ in Magento 2 — async processing voor grote shops

AuthorRuthger Idema
24 april 202611 min leestijd

Een bulkimport van 50.000 producten die de frontend 8 minuten blokkeert. Orderverwerking die vastloopt tijdens piekuren. RabbitMQ lost dit op. Zo configureer je het correct.

RabbitMQ in Magento 2 — async processing voor grote shops

Een bulkimport van 50.000 producten die 8 minuten de frontend blokkeert. Een orderverwerking die vastloopt omdat tien tegelijkertijd binnenkomende orders dezelfde database-tabellen proberen te vergrendelen. Een e-mailqueue die oploopt tot 40.000 berichten omdat de verzending synchroon in de request-lifecycle zit.

Dit zijn symptomen van hetzelfde probleem: synchrone verwerking van zware taken in een omgeving die daarvoor niet gebouwd is.

RabbitMQ lost dit op. Dit artikel legt uit hoe message queues in Magento werken, hoe je RabbitMQ configureert en welke use cases echt profiteren van async processing.

Wat je leert in dit artikel

  • Hoe Magento's message queue framework werkt
  • Wanneer je RabbitMQ nodig hebt (en wanneer MySQL queue volstaat)
  • Volledige configuratie van RabbitMQ in Magento 2
  • Use cases: bulk operations, orderverwerking, ERP-synchronisatie
  • Monitoring en troubleshooting van message queues

Message queues in Magento — de basis

Magento 2.3+ heeft een ingebouwd Message Queue Framework (MQF). Dit framework stelt je in staat om taken asynchroon te verwerken via een producer-consumer-patroon.

Producer (gooit bericht in queue)
    ↓
Message Queue (opslag)
    ↓
Consumer (verwerkt bericht)
Producer: de code die een taak aanmaakt en in de queue plaatst. Message: de payload met instructies voor de consumer. Queue: de opslaglaag (MySQL of RabbitMQ). Consumer: een achtergrondproces dat berichten verwerkt.

Magento ondersteunt twee queue-backends:

  1. MySQL — geschikt voor lage volumes, geen extra infrastructuur nodig
  2. RabbitMQ — geschikt voor hoge volumes, parallelle consumers, complexe routing

Wanneer kies je RabbitMQ boven MySQL queue?

ScenarioMySQL QueueRabbitMQ
< 1.000 berichten per uurPrimaOverkill
> 10.000 berichten per uurProblemenNoodzakelijk
Parallelle consumersBeperktUitstekend
Dead letter handlingNiet nativeIngebouwd
Message prioriteitNiet mogelijkMogelijk
Meerdere consumerende servicesComplexNatively ondersteund
Monitoring en management UIGeenIngebouwd

De vuistregel: zodra je regelmatig meer dan 5.000 berichten per uur verwerkt, of zodra je parallelle verwerking nodig hebt, overstap je naar RabbitMQ.

RabbitMQ installeren en configureren

Installatie

bash
# Ubuntu/Debian
apt-get install rabbitmq-server

# RabbitMQ Management Plugin activeren (web UI)
rabbitmq-plugins enable rabbitmq_management

# Service starten
systemctl start rabbitmq-server
systemctl enable rabbitmq-server

# Admin gebruiker aanmaken
rabbitmqctl add_user magento SterkWachtwoord123
rabbitmqctl set_permissions -p / magento ".*" ".*" ".*"
rabbitmqctl set_user_tags magento administrator

De management UI is daarna beschikbaar op http://server:15672.

Magento configuratie

php
// app/etc/env.php
'queue' => [
    'amqp' => [
        'host'     => 'localhost',
        'port'     => '5672',
        'user'     => 'magento',
        'password' => 'SterkWachtwoord123',
        'virtualhost' => '/',
        'ssl'      => false,
    ],
    'consumers_wait_for_messages' => 0,
],

Verifieer de verbinding:

bash
php bin/magento queue:consumers:list

Als de verbinding werkt, zie je een lijst van beschikbare consumers.

Een custom message queue implementeren

Stel: je hebt een ERP-koppeling waarbij orderbevestigingen asynchroon naar het ERP gestuurd moeten worden. Synchrone verzending in de checkout blokkeert de klant als het ERP traag reageert.

Stap 1: communicatie.xml definiëren

xml
<!-- app/code/Vendor/ErpConnector/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.erp.order.export"
           request="Vendor\ErpConnector\Api\Data\OrderExportRequestInterface"/>

</config>

Stap 2: queue_consumer.xml configureren

xml
<!-- app/code/Vendor/ErpConnector/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.erp.order.export.consumer"
              queue="vendor.erp.order.export"
              connection="amqp"
              maxMessages="1000"
              handler="Vendor\ErpConnector\Model\Consumer\OrderExportConsumer::process"/>

</config>

Stap 3: queue_topology.xml voor RabbitMQ routing

xml
<!-- app/code/Vendor/ErpConnector/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-db"
              type="topic"
              connection="amqp">
        <binding id="vendor.erp.order.export"
                 topic="vendor.erp.order.export"
                 destinationType="queue"
                 destination="vendor.erp.order.export"/>
    </exchange>

</config>

Stap 4: queue_publisher.xml

xml
<!-- app/code/Vendor/ErpConnector/etc/queue_publisher.xml -->
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/publisher.xsd">

    <publisher topic="vendor.erp.order.export">
        <connection name="amqp" exchange="magento-db"/>
    </publisher>

</config>

Stap 5: de Producer — order in queue plaatsen

php
<?php

namespace Vendor\ErpConnector\Observer;

use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\MessageQueue\PublisherInterface;
use Vendor\ErpConnector\Api\Data\OrderExportRequestInterfaceFactory;

class OrderPlaceAfterObserver implements ObserverInterface
{
    public function __construct(
        private PublisherInterface $publisher,
        private OrderExportRequestInterfaceFactory $requestFactory
    ) {}

    public function execute(Observer $observer): void
    {
        $order = $observer->getEvent()->getOrder();

        // Maak het export-verzoek aan
        $exportRequest = $this->requestFactory->create();
        $exportRequest->setOrderId((int) $order->getId());
        $exportRequest->setOrderIncrementId($order->getIncrementId());

        // Gooi het bericht in de queue — niet-blokkerend
        $this->publisher->publish('vendor.erp.order.export', $exportRequest);

        // De checkout gaat direct door; ERP-export gebeurt op de achtergrond
    }
}

Stap 6: de Consumer — berichten verwerken

php
<?php

namespace Vendor\ErpConnector\Model\Consumer;

use Vendor\ErpConnector\Api\Data\OrderExportRequestInterface;
use Vendor\ErpConnector\Model\ErpClient;
use Psr\Log\LoggerInterface;

class OrderExportConsumer
{
    public function __construct(
        private ErpClient $erpClient,
        private LoggerInterface $logger
    ) {}

    public function process(OrderExportRequestInterface $request): void
    {
        try {
            // Verstuur order naar ERP — mag langzaam zijn, blokkeert niets
            $result = $this->erpClient->exportOrder([
                'order_id'            => $request->getOrderId(),
                'order_increment_id'  => $request->getOrderIncrementId(),
            ]);

            $this->logger->info(
                "Order {$request->getOrderIncrementId()} succesvol geëxporteerd naar ERP",
                ['erp_reference' => $result['reference']]
            );

        } catch (\Exception $e) {
            $this->logger->error(
                "ERP-export mislukt voor order {$request->getOrderIncrementId()}",
                ['error' => $e->getMessage()]
            );

            // Gooi een exception om het bericht terug in de queue te plaatsen
            throw $e;
        }
    }
}

Consumers starten

Consumers zijn lange-lopende CLI-processen. Start ze via Supervisor of een cron-job.

Via Supervisor (aanbevolen voor productie)

ini
; /etc/supervisor/conf.d/magento-consumers.conf

[program:vendor_erp_order_export]
command=php /var/www/magento/bin/magento queue:consumers:start vendor.erp.order.export.consumer --max-messages=10000
directory=/var/www/magento
user=www-data
numprocs=3
autostart=true
autorestart=true
stderr_logfile=/var/log/magento/consumer-erp-order.err.log
stdout_logfile=/var/log/magento/consumer-erp-order.log
numprocs=3 start drie parallelle consumers. Drie processen verwerken berichten tegelijkertijd. Voor hoge volumes verhoog je dit getal.
bash
# Supervisor herladen
supervisorctl reread
supervisorctl update
supervisorctl status

Bulk operations met message queues

Magento's bulk operations framework (asynchrone bulk REST API) is gebouwd op RabbitMQ. Hiermee kun je operaties op duizenden records initiëren via de API en de verwerking asynchroon laten verlopen.

bash
# Voorbeeld: bulk product update via async REST API
curl -X POST "https://jouwshop.nl/rest/async/bulk/V1/products" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '[
    {"product": {"sku": "PROD-001", "price": 29.99}},
    {"product": {"sku": "PROD-002", "price": 39.99}},
    {"product": {"sku": "PROD-003", "price": 49.99}}
  ]'

De API retourneert direct een bulk_uuid. De feitelijke verwerking gebeurt op de achtergrond.

json
{
  "bulk_uuid": "7197c4e6-3c79-4b34-b77f-5f37d0f5f02a",
  "request_items": [
    {"id": 0, "data_hash": "abc123", "status": "accepted"},
    {"id": 1, "data_hash": "def456", "status": "accepted"},
    {"id": 2, "data_hash": "ghi789", "status": "accepted"}
  ],
  "errors": false
}

Statuscheck achteraf:

bash
# Controleer de verwerkingsstatus van de bulk operatie
curl "https://jouwshop.nl/rest/V1/bulk/7197c4e6-3c79-4b34-b77f-5f37d0f5f02a/status" \
  -H "Authorization: Bearer {token}"

Dead letter queues — wat te doen met mislukte berichten

Een bericht dat consistent faalt, moet niet eindeloos opnieuw verwerkt worden. RabbitMQ biedt dead letter queues: een aparte queue voor berichten die de maximale retry-limiet hebben bereikt.

xml
<!-- queue_topology.xml: dead letter queue toevoegen -->
<exchange name="magento-db"
          type="topic"
          connection="amqp">

    <binding id="vendor.erp.order.export"
             topic="vendor.erp.order.export"
             destinationType="queue"
             destination="vendor.erp.order.export">
        <arguments>
            <!-- Na 3 mislukte pogingen naar dead letter queue -->
            <argument name="x-dead-letter-exchange" xsi:type="string">magento-db</argument>
            <argument name="x-dead-letter-routing-key" xsi:type="string">vendor.erp.order.export.dead</argument>
            <argument name="x-message-ttl" xsi:type="number">86400000</argument>
        </arguments>
    </binding>

    <!-- Dead letter queue definitie -->
    <binding id="vendor.erp.order.export.dead"
             topic="vendor.erp.order.export.dead"
             destinationType="queue"
             destination="vendor.erp.order.export.dead"/>

</exchange>

Berichten in de dead letter queue kun je monitoren via de RabbitMQ management UI en handmatig opnieuw verwerken of exporteren voor analyse.

Monitoring en performance

RabbitMQ Management UI

De management UI op poort 15672 geeft realtime inzicht in:

  • Queue-diepte (hoeveel berichten wachten op verwerking)
  • Consumer-activiteit (zijn er consumers actief?)
  • Publish rate vs consume rate
  • Memory en disk gebruik

Een queue die gestaag groeit zonder dat de consume rate de publish rate bijhoudt, is een early warning: je hebt meer consumers nodig of je consumer is te langzaam.

Performance benchmarks

ScenarioMySQL QueueRabbitMQ (1 consumer)RabbitMQ (5 consumers)
1.000 orders/uur320ms/bericht45ms/bericht45ms/bericht
10.000 orders/uurOverloaded48ms/bericht46ms/bericht
50.000 orders/uurNiet mogelijkAchterstand52ms/bericht
Bulk import 10.000 producten18 min4 min52 sec

Vijf parallelle consumers voor bulk productimport: van 18 minuten naar 52 seconden.

Productie-checklist

Voordat je RabbitMQ in productie neerzet:

  • [ ] RabbitMQ geconfigureerd met persistent messages (berichten overleven een restart)
  • [ ] Supervisor of systemd geconfigureerd voor consumer-processen
  • [ ] Dead letter queues geconfigureerd voor mislukte berichten
  • [ ] Memory- en disk-alerting op RabbitMQ-server
  • [ ] Queue-diepte monitoring geconfigureerd
  • [ ] Alerting bij consumers die zijn gestopt
  • [ ] Backup-strategie voor RabbitMQ data

Bekijk ook Magento voor onze diensten en ons artikel over Magento 2 grote catalogus performance voor aanvullende optimalisaties. Voor complexe integraties met RabbitMQ is Alumio als iPaaS-platform een krachtige aanvulling.

Conclusie

RabbitMQ is geen silver bullet. Voor een webshop met een beperkt berichtvolume is MySQL queue voldoende en is RabbitMQ overkill.

Maar zodra je zware background-taken hebt — bulk imports, ERP-synchronisatie, orderverwerking op schaal — is RabbitMQ de juiste infrastructuurkeuze. Snellere verwerking, betere observeerbaarheid, ingebouwde retry-logica en de mogelijkheid om horizontaal te schalen door meer consumers toe te voegen.

De implementatie is werkdagen werk, niet weken. De performance-impact is direct meetbaar.

Heb je te maken met trage bulk-operaties of een instabiele orderverwerking tijdens piekuren? Neem contact op — wij analyseren de bottlenecks en implementeren de juiste oplossing.

Veelgestelde vragen

Werkt RabbitMQ ook met Magento Cloud?

Adobe Commerce Cloud heeft RabbitMQ ingebouwd en geconfigureerd. Voor on-premise en andere cloud-omgevingen is het een aparte installatietaak.

Hoeveel consumers moet ik starten?

Begin met één consumer per queue en meet de queue-diepte. Als berichten sneller binnenkomen dan verwerkt worden, voeg je consumers toe. Voor hoge volumes met snelle verwerkingstaken zijn 3-10 consumers typisch.

Wat als RabbitMQ uitvalt?

Magento valt automatisch terug op MySQL queue als de AMQP-verbinding niet beschikbaar is. Berichten die gepubliceerd worden terwijl RabbitMQ offline is, worden in MySQL opgeslagen en verwerkt zodra de verbinding hersteld is.

Kan ik RabbitMQ ook gebruiken voor communicatie tussen Magento en een externe service?

Ja. RabbitMQ is niet Magento-specifiek. Je kunt een Laravel-applicatie of een Python-service als consumer configureren die berichten van Magento verwerkt. Zorg wel voor een gedeeld berichtformaat.

Ruthger Idema

Geschreven door Ruthger Idema

15+ jaar ervaring in e-commerce development. Gespecialiseerd in Magento, Shopify en Laravel maatwerk.

Meer over ons team →
Deel dit artikel:

Wil je jouw e-commerce naar het volgende niveau?

Plan een vrijblijvend gesprek met onze experts over Magento, Shopify of Laravel maatwerk.

Plan een Tech Check