اتخطّى للمحتوى

المرحلة 03 · الـ APIs والتكاملدرس 15 من 219 دقيقة قراءةآخر تحديث:

Lesson 15 / 21

RabbitMQ × Magentoمن الصفر لموديول شغّال.

هنفهم الـ Message Queue في Magento من الأساس، وبعدين نبني module شغّال خطوة بخطوة: publisher بيبعت رسالة، وconsumer بياخدها ويعالجها في الخلفية. كل ملف مشروح ودوره واضح.

● عملي كامل 4 ملفات إعداد Publisher + Consumer

Magento 2 بيتعامل مع RabbitMQ عن طريق Message Queue Framework: بتعرّف الـ topic في communication.xml، والـ exchange والـ queue في queue_topology.xml، والـ consumer في queue_consumer.xml، والـ publisher في queue_publisher.xml. الـ publisher class بيبعت الرسالة، والـ consumer بيعالجها في الخلفية، وبتشغّله بأمر bin/magento queue:consumers:start.

// إزاي تستخدمه الجزء الأول مفاهيم (افهمها الأول). الجزء الثاني بناء عملي بالترتيب — كل خطوة ملف. الفكرة اللي بننفّذها: لما order يتعمل، نبعت بياناته لـ queue، وconsumer يعالجها (يسجّلها في log كمثال بسيط، وممكن تبقى إرسال لـ ERP). امشي بالترتيب متقفزش خطوة.
◆ Part 1 — المفاهيم
01

المفاهيم الأساسية

المصطلحات اللازمة قبل ما نبني.

Publisher
Exchange
Queue
Consumer
  • Publisher — الجزء اللي بيبعت الرسالة (بيحطها في النظام).
  • Exchange — "موزّع البريد" — بياخد الرسالة ويقرّر تروح لأنهي queue حسب قواعد (routing).
  • Queue — الطابور اللي بتستنى فيه الرسائل لحد ما تتعالج.
  • Consumer — الجزء اللي بياخد الرسائل من الـ queue وينفّذها.
  • Topic — اسم/عنوان الرسالة، بيربط الـ publisher بالـ consumer الصح.
تشبيه زي مكتب البريد. أنت (publisher) بتبعت جواب. مكتب البريد (exchange) بيقرأ العنوان ويحطّه في الصندوق الصح (queue). ساعي البريد (consumer) بياخد الجوابات من الصندوق ويوصّلها. الـ topic هو العنوان اللي بيوجّه كل ده.
i
الفكرة الجوهرية: الـ publisher والـ consumer مايعرفوش بعض. الـ publisher بيرمي الرسالة في النظام ويمشي، والـ consumer بياخدها لما يكون فاضي. ده الـ decoupling اللي بيخلّي العمليات مستقلة.
• • •
02

MQF في Magento

إزاي Magento بيغلّف RabbitMQ.

إيه هو

الـ MQF (Message Queue Framework) هو طبقة في Magento بتغلّف RabbitMQ. بدل ما تتعامل مع RabbitMQ مباشرة، بتعرّف كل حاجة في ملفات XML، وMagento بيتولّى الباقي.

ليه ملفات XML

عشان يفصل الإعداد (فين الرسالة رايحة) عن الكود (إيه اللي بيتعمل). ده بيخلّي النظام مرن — تقدر تغيّر التوجيه من غير ما تلمس الكود.

i
لو RabbitMQ مش متوفّر، Magento بيستخدم MySQL كـ queue بشكل افتراضي (أبطأ). بس في production الجدّي، RabbitMQ هو الأفضل. الإعداد بيتحط في env.php.
• • •
03

خريطة الملفات

الملفات اللي هنعملها ودور كل واحد. الصورة الكاملة قبل ما نبدأ.

communication.xmlبيعرّف الـ topic (اسم الرسالة) ونوع البيانات اللي بتتبعت.
queue_topology.xmlبيعرّف الـ exchange وإزاي بيوجّه الرسائل للـ queues (الـ routing).
queue_consumer.xmlبيربط الـ queue بالـ consumer class اللي هيعالجها.
queue_publisher.xmlبيعرّف إزاي الـ topic بيتنشر (لأي exchange).
Publisher.phpالكود اللي بيبعت الرسالة (بينده الـ topic).
Consumer.phpالكود اللي بيستقبل الرسالة ويعالجها.
!
الأربع ملفات XML دول بيتحطوا في etc/ (global). سهل تختلط: communication = إيه الرسالة، topology = التوجيه، consumer = مين يعالج، publisher = إزاي تتنشر. هنشرح كل واحد لوحده.
تشبيه فكّر فيهم كـ إعداد مكتب بريد: communication (نوع الطرد)، topology (خريطة التوزيع)، consumer (مين المستلم)، publisher (إزاي تبعت). الكود بس بيستخدم الإعداد ده.
• • •
◆ Part 2 — البناء العملي
04

خطوة 1: الموديول

نبدأ بالملفين الأساسيين لأي موديول.

registration.phpphp
use Magento\Framework\Component\ComponentRegistrar;

ComponentRegistrar::register(
    ComponentRegistrar::MODULE,
    'Vendor_QueueDemo',
    __DIR__
);
etc/module.xmlxml
<config>
  <module name="Vendor_QueueDemo">
    <sequence>
      <module name="Magento_Sales"/>
    </sequence>
  </module>
</config>
i
حطّينا Magento_Sales في الـ sequence لأن مثالنا هيتعامل مع الـ orders. لو موديولك مش محتاج، شيلها.
• • •
05

خطوة 2: communication.xml

نعرّف الـ topic — اسم الرسالة ونوع بياناتها.

دوره

بيعرّف الـ topic (عنوان الرسالة) ونوع البيانات اللي بتتبعت معاها (request). ده العقد اللي الـ publisher والـ consumer بيتفقوا عليه.

etc/communication.xmlxml
<config>
  <topic name="vendor.queuedemo.process"
    request="string"
    handler="Vendor\QueueDemo\Model\Consumer::process"/>
</config>
شرح السطور
  • name — اسم الـ topic. هنستخدمه في كل الملفات التانية.
  • request — نوع البيانات. هنا string (بسيط). ممكن يكون interface لبيانات معقّدة.
  • handler — الـ method اللي هتعالج الرسالة (في الـ consumer).
i
الـ request="string" بيبسّط المثال. في الواقع بتبعت غالبًا data interface (زي OrderInterface) عشان بيانات منظّمة. بس للتعلّم، string كفاية.
• • •
06

خطوة 3: queue_topology.xml

نعرّف الـ exchange وإزاي بيوجّه الرسالة للـ queue.

دوره

بيعرّف الـ exchange (الموزّع) والـ binding — القاعدة اللي بتربط الـ topic بالـ queue. يعني "الرسالة بتاعة topic كذا، تروح queue كذا".

etc/queue_topology.xmlxml
<config>
  <exchange name="magento-demo"
    type="topic" connection="amqp">
    <binding id="demoBinding"
      topic="vendor.queuedemo.process"
      destinationType="queue"
      destination="vendor.queuedemo.queue"/>
  </exchange>
</config>
شرح السطور
  • exchange name — اسم الموزّع.
  • connection="amqp" — يعني RabbitMQ (amqp البروتوكول). لو db يبقى MySQL.
  • binding — بيربط الـ topic بالـ queue المحدّدة في destination.
i
الـ type="topic" بيسمح بتوجيه مرن بالأنماط (wildcards). لو الرسالة تروح queue واحدة بس، ممكن يبقى بسيط.
• • •
07

خطوة 4: queue_consumer.xml

نربط الـ queue بالـ consumer class.

دوره

بيعرّف الـ consumer — بيقول "الـ queue دي، الكلاس ده هو اللي بيعالجها". وبيدّي الـ consumer اسم نستخدمه في التشغيل.

etc/queue_consumer.xmlxml
<config>
  <consumer name="vendor.queuedemo.consumer"
    queue="vendor.queuedemo.queue"
    connection="amqp"
    handler="Vendor\QueueDemo\Model\Consumer::process"/>
</config>
  • name — اسم الـ consumer (هنستخدمه في الـ CLI للتشغيل).
  • queue — الـ queue اللي بيسمع منها (نفس اللي في topology).
  • handler — الكلاس والـ method اللي بتعالج.
i
الـ name ده مهم — هو اللي هتكتبه في bin/magento queue:consumers:start عشان تشغّل الـ consumer.
• • •
08

خطوة 5: queue_publisher.xml

نعرّف إزاي الـ topic بيتنشر.

دوره

بيقول "الـ topic ده بيتنشر على أنهي exchange وconnection". بيكمّل الدايرة — بيربط الـ topic بالـ exchange اللي عرّفناه في topology.

etc/queue_publisher.xmlxml
<config>
  <publisher topic="vendor.queuedemo.process">
    <connection name="amqp"
      exchange="magento-demo"/>
  </publisher>
</config>
i
لاحظ الترابط: الـ topic (من communication) بيتنشر على الـ exchange (من topology)، اللي بيوجّهه للـ queue، اللي الـ consumer بيسمعها. كل ملف بيربط جزء.
• • •
09

خطوة 6: Publisher class

الكود اللي بيبعت الرسالة فعليًا.

دوره

بيستخدم الـ PublisherInterface عشان يبعت رسالة للـ topic. أي حد عايز يبعت، بينده الكلاس ده.

Model/Publisher.phpphp
namespace Vendor\QueueDemo\Model;

use Magento\Framework\MessageQueue\PublisherInterface;

class Publisher
{
    private const TOPIC = 'vendor.queuedemo.process';

    public function __construct(
        private readonly PublisherInterface $publisher
    ) {}

    public function execute(string $message): void
    {
        // send the message to the queue
        $this->publisher->publish(
            self::TOPIC,
            $message
        );
    }
}
i
بس كده — الـ publisher بسيط. بيحقن الـ PublisherInterface (شفنا الـ DI في artifacts سابقة)، وبينده publish() بالـ topic والرسالة. مبيستناش نتيجة — بيبعت ويكمّل.
• • •
10

خطوة 7: Consumer class

الكود اللي بيستقبل الرسالة ويعالجها.

دوره

فيه الـ process() method (اللي عرّفناها كـ handler). دي بتشتغل لما رسالة توصل. هنا بنكتب المنطق — في المثال، نسجّل في log.

Model/Consumer.phpphp
namespace Vendor\QueueDemo\Model;

use Psr\Log\LoggerInterface;

class Consumer
{
    public function __construct(
        private readonly LoggerInterface $logger
    ) {}

    // runs when a message arrives
    public function process(string $message): void
    {
        // your logic here (e.g. send to ERP)
        $this->logger->info(
            'QueueDemo received: ' . $message
        );
    }
}
!
هنا المكان اللي بتحط فيه المنطق الحقيقي — إرسال لـ ERP، معالجة، الخ. ولو العملية ممكن تتكرّر، ضيف idempotency هنا (تشيك إنك مانفّذتش نفس الرسالة قبل كده).
• • •
◆ Part 3 — التشغيل
11

خطوة 8: التشغيل والاختبار

نفعّل الموديول ونشغّل الـ consumer ونجرّب.

terminalbash
# 1. فعّل الموديول
bin/magento module:enable Vendor_QueueDemo
bin/magento setup:upgrade
bin/magento cache:clean

# 2. شغّل الـ consumer (بيسمع للرسائل)
bin/magento queue:consumers:start \
  vendor.queuedemo.consumer

# للاختبار: شغّله لعدد محدود من الرسائل
bin/magento queue:consumers:start \
  vendor.queuedemo.consumer --max-messages=10
إزاي تجرّب النشر

تنده الـ Publisher من أي مكان — observer، controller، أو command. مثلًا observer على sales_order_place_after بينده $publisher->execute('Order #123 placed').

تتأكد إنه اشتغل

بعد ما تبعت رسالة والـ consumer شغّال، تشوف الرسالة في الـ log (var/log/). لو ظهرت "QueueDemo received..." — تمام، الدايرة كاملة اشتغلت.

!
في production، الـ consumers لازم تفضل شغّالة دايمًا. Magento بيديرها عن طريق cron أو supervisor (أداة بتضمن إن الـ process يفضل شغّال ويرجع لو وقع).
i
لو غيّرت أي ملف XML، اعمل setup:upgrade وcache:clean. ولو الـ consumer شغّال، أعد تشغيله عشان ياخد التغييرات.
الدايرة كاملة
  • الـ Publisher.php بينده publish(topic, msg).
  • الـ publisher.xml بيوجّه الـ topic للـ exchange.
  • الـ topology.xml (exchange) بيوجّهه للـ queue.
  • الرسالة بتستنى في الـ queue.
  • الـ consumer.xml بيقول مين يعالج الـ queue دي.
  • الـ Consumer.php بياخد الرسالة ويعالجها في الخلفية.
i
لو فهمت الدايرة دي، فهمت الـ MQ في Magento بالكامل. الباقي تفاصيل (data interfaces بدل string، معالجة أعقد، idempotency).

موديول RabbitMQ شغّال ✓

دلوقتي عندك module كامل: publisher بيبعت، 4 ملفات XML بيوجّهوا، وconsumer بيعالج في الخلفية. فهمت المفاهيم والبناء والتشغيل من الصفر.

الخلاصة: الـ topic بيربط الكل — من communication للـ publisher للـ exchange للـ queue للـ consumer. دي الدايرة اللي أي message queue في Magento بيمشي عليها. الباقي مجرد منطق أعقد جوّه الـ consumer.

// magento 2 · rabbitmq · publisher → queue → consumer

خلّصت الدرس؟علّمه عشان تتابع تقدّمك في الكورس.

كاتب الدرس

Abdulrahman Masoud

عندك سؤال على الدرس أو محتاج مساعدة في مشروع Magento؟ كلّمني.

أسئلة شائعة

إزاي أستخدم RabbitMQ في Magento 2؟

Magento بيغلّف RabbitMQ بطبقة اسمها Message Queue Framework (MQF)، فبدل ما تتعامل معاه مباشرة بتعرّف كل حاجة في ملفات XML جوّه etc/. بتكتب publisher class بينادي publish() على topic، وconsumer class بيعالج الرسالة، وبتشغّل الـ consumer بـ bin/magento queue:consumers:start.

ما الفرق بين communication.xml و queue_topology.xml و queue_consumer.xml و queue_publisher.xml؟

الـ communication.xml بيعرّف الـ topic ونوع البيانات اللي بتتبعت، والـ queue_topology.xml بيعرّف الـ exchange والـ binding اللي بيوجّه الـ topic لـ queue معيّنة. الـ queue_consumer.xml بيربط الـ queue بالكلاس اللي هيعالجها، أما queue_publisher.xml فبيحدد الـ topic بيتنشر على أنهي exchange وconnection.

يعني إيه Publisher و Exchange و Queue و Consumer في RabbitMQ؟

الـ Publisher بيبعت الرسالة، والـ Exchange بياخدها ويقرّر تروح لأنهي queue حسب قواعد الـ routing، والـ Queue هي الطابور اللي الرسالة بتستنى فيه، والـ Consumer بياخدها وينفّذها. والـ Topic هو اسم الرسالة اللي بيربط الكل. الميزة إن الـ publisher والـ consumer مايعرفوش بعض، وده الـ decoupling اللي بيخلّي الشغل يتم في الخلفية.

إزاي أشغّل consumer في Magento 2؟

بتكتب bin/magento queue:consumers:start وبعده اسم الـ consumer المعرّف في queue_consumer.xml، ولو بتجرّب ضيف --max-messages=10 عشان يعالج عدد محدود. في production الـ consumers لازم تفضل شغّالة دايمًا عن طريق cron أو supervisor، ولو غيّرت ملفات الـ XML اعمل setup:upgrade وcache:clean وأعد تشغيل الـ consumer.

هل ينفع أستخدم message queue في Magento 2 من غير RabbitMQ؟

أيوه، Magento يقدر يستخدم MySQL كـ queue، وده بيتحدد بالـ connection: amqp يعني RabbitMQ وdb يعني MySQL. بس الـ MySQL أبطأ، وفي production الجدّي RabbitMQ هو الاختيار الأفضل، وإعداده بيتحط في env.php.

إزاي أبعت بيانات الأوردر لـ queue لما order يتعمل في Magento 2؟

اعمل observer على event sales_order_place_after وخليه ينادي الـ Publisher class بتاعك، اللي بيستخدم PublisherInterface::publish() بالـ topic والرسالة. الـ publisher مبيستناش نتيجة، والـ consumer هو اللي بيعالج الرسالة في الخلفية، زي إنه يسجّلها في log أو يبعتها لـ ERP.