<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>gj |</title>
	<atom:link href="https://blog.gaiterjones.com/category/magento2/message-queues/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.gaiterjones.com/category/magento2/message-queues/</link>
	<description>gaiterjones</description>
	<lastBuildDate>Thu, 18 Feb 2021 15:45:37 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.4.3</generator>
	<item>
		<title>Magento 2 Asynchronous Message Queue Management with RabbitMQ</title>
		<link>https://blog.gaiterjones.com/magento-2-asynchronous-message-queue-management/</link>
					<comments>https://blog.gaiterjones.com/magento-2-asynchronous-message-queue-management/#respond</comments>
		
		<dc:creator><![CDATA[PAJ]]></dc:creator>
		<pubDate>Sat, 13 Feb 2021 18:00:15 +0000</pubDate>
				<category><![CDATA[Magento2]]></category>
		<category><![CDATA[Message Queues]]></category>
		<category><![CDATA[AMQP]]></category>
		<category><![CDATA[Magento 2 Message Queues]]></category>
		<category><![CDATA[RabbitMQ]]></category>
		<guid isPermaLink="false">https://blog.gaiterjones.com/?p=2387</guid>

					<description><![CDATA[The Magento Message Queue Framework was made available in the Open Source version of Magento with version 2.3 and provides a standards based system for modules to publish messages to...<a class="more-link" href="https://blog.gaiterjones.com/magento-2-asynchronous-message-queue-management/" title="Continue reading">Continue reading</a>]]></description>
										<content:encoded><![CDATA[<p>The Magento Message Queue Framework was made available in the Open Source version of Magento with version 2.3 and provides a standards based system for modules to publish messages to queues and also defines the consumers that will receive the messages asynchronously.</p>
<h1>What are Asynchronous Message Queues?</h1>
<p>The normal way for a module to process data caused by some kind of front or backend action is to create an observer that listens for the specific Magento event and then processes the event data in some way. For example if you want to process order data whenever an order is placed, you would create a custom module with an order event observer. When a customer places an order the event will be fired and your module can process the order data.</p>
<p>This event type processing occurs synchronously with the event. This can be a problem if your process is intensive and takes some time to complete, or if for some reason it causes an error. Synchronous processing of events may cause delays for the customer in frontend processes.</p>
<p>Asynchronous Message Queues allow your event to be placed in a queuing system and processed by your modules consumer <em>as soon as possible</em>.</p>
<p>The Magento Message Queue Framework consists of the following components:</p>
<ul>
<li>Publisher<br />
A publisher is a component that sends messages to an exchange.
        </li>
<li>Exchange <br />
An exchange receives messages from publishers and sends them to queues.
        </li>
<li>Queue<br />
A queue is a buffer that stores messages.
        </li>
<li>Consumer<br />
A consumer receives messages. It knows which queue to <em>consume</em>.
        </li>
</ul>
<p>By default Magento 2 uses the MySQL database as the Exchange and Queue system for messages. It does this with a MySQL adapter, Message data is stored in the <code>queue, queue_message, queue_message_status</code> tables. Magento uses the cron job <code>consumers_runner</code> to manage queued messages by starting (or restarting) message consumers.</p>
<p>The fastest this can happen with the Magento cron system is once every 60 seconds. The job is configured in the <em>MessageQueue </em>module. </p>
<pre class="brush: plain; title: ; notranslate">
job name=&quot;consumers_runner&quot; instance=&quot;Magento\MessageQueue\Model\Cron\ConsumersRunner&quot; method=&quot;run&quot;&gt;
    &lt;schedule&gt;* * * * *&lt;/schedule&gt;
&lt;/job&gt;
</pre>
<p>I recommend looking at <code>Magento\MessageQueue\Model\Cron\ConsumersRunner</code> to understand how the default Magento consumers are managed.</p>
<p>If you want to list all the default consumers available in Magento 2 use the command <code>bin/magento queue:consumers:list</code></p>
<span class="collapseomatic collapse" id="id66036cef2065b"  tabindex="0" title="Default message consumers/queues in Magento 2.4.2"    >Default message consumers/queues in Magento 2.4.2</span><div id="target-id66036cef2065b" class="collapseomatic_content ">
[text]
product_action_attribute.update<br />
product_action_attribute.website.update<br />
exportProcessor<br />
inventory.source.items.cleanup<br />
inventory.mass.update<br />
inventory.reservations.cleanup<br />
inventory.reservations.update<br />
codegeneratorProcessor<br />
media.storage.catalog.image.resize<br />
inventory.reservations.updateSalabilityStatus<br />
inventory.indexer.sourceItem<br />
inventory.indexer.stock<br />
media.content.synchronization<br />
media.gallery.renditions.update<br />
media.gallery.synchronization<br />
async.operations.all<br />
[/text]
</div>
<p>&nbsp;</p>
<h3>Using the Magento database for messaging is not very scalable</h3>
<blockquote><p>RabbitMQ should be used whenever possible.</p></blockquote>
<h1>Converting Magento 2 Message Queues to Rabbit MQ AMQP</h1>
<p><a href="http://rabbitmq.com" rel="noopener" target="_blank">RabbitMQ</a> is an open source message broker system and the Magento Message Queue Framework has built in support for RabbitMQ as a scalable platform for sending and receiving messages. RabbitMQ is based on the Advanced Message Queuing Protocol (AMQP) 0.9.1 specification.</p>
<p>Configuring Magento 2 to use RabbitMQ requires the addition of a new queue node in <code>app/etc/env.php</code></p>
<pre class="brush: plain; title: ; notranslate">
    'queue' =&gt; &#x5B;
        'amqp' =&gt; &#x5B;
            'host' =&gt; '&lt;rabbitmq_host&gt;',
            'port' =&gt; '&lt;rabbitmq_port&gt;',
            'user' =&gt; '&lt;rabbitmq_user&gt;',
            'password' =&gt; '&lt;rabbitmq_pass&gt;',
            'virtualhost' =&gt; '/',
            'ssl' =&gt; false
        ],
     ]
</pre>
<p>Enabling message queues for RabbitMQ AMQP is simply a case of changing the configuration of the queue from DB to AMQP.</p>
<p><code>connection="amqp"</code></p>
<p>One built in message queue is by default configured to use AMQP this is the <code>async.operations.all</code> queue. If you have successfully configured RabbitMQ you should see this queue in the admin interface</p>
<figure id="attachment_2391" aria-describedby="caption-attachment-2391" style="width: 600px" class="wp-caption aligncenter"><img fetchpriority="high" decoding="async" src="https://blog.gaiterjones.com/wp-content/uploads/2021/02/mq_1.jpg" alt="Default AMQP Message Queue" width="600" height="199" class="size-full wp-image-2391" srcset="https://blog.gaiterjones.com/wp-content/uploads/2021/02/mq_1.jpg 600w, https://blog.gaiterjones.com/wp-content/uploads/2021/02/mq_1-440x146.jpg 440w, https://blog.gaiterjones.com/wp-content/uploads/2021/02/mq_1-550x182.jpg 550w" sizes="(max-width: 600px) 100vw, 600px" /><figcaption id="caption-attachment-2391" class="wp-caption-text">Default AMQP Message Queue</figcaption></figure>
<p>When creating message queues for new modules you should configure them to use AMQP, check out <a href="https://github.com/gaiterjones/Magento2_Gaiterjones_Rabbitmq">this module</a> for an example module using a product save event message.</p>
<p>If you want to convert existing MySQL DB message queues to use AMQP you can accomplish this using extra nodes in the <code>env.php</code> queue configuration. This example is taken from the <a href="http://Magento\MessageQueue\Model\Cron\ConsumersRunner">official documentation</a> for <code>product_action_attribute.update</code> queue:</p>
<pre class="brush: plain; title: ; notranslate">
'queue' =&gt; &#x5B;
    'topics' =&gt; &#x5B;
        'product_action_attribute.update' =&gt; &#x5B;
            'publisher' =&gt; 'amqp-magento'
        ]
    ],
    'config' =&gt; &#x5B;
        'publishers' =&gt; &#x5B;
            'product_action_attribute.update' =&gt; &#x5B;
                'connections' =&gt; &#x5B;
                    'amqp' =&gt; &#x5B;
                        'name' =&gt; 'amqp',
                        'exchange' =&gt; 'magento',
                        'disabled' =&gt; false
                    ],
                    'db' =&gt; &#x5B;
                        'name' =&gt; 'db',
                        'disabled' =&gt; true
                    ]
                ]
            ]
        ]
    ],
    'consumers' =&gt; &#x5B;
        'product_action_attribute.update' =&gt; &#x5B;
            'connection' =&gt; 'amqp',
        ],
    ],
],
</pre>
<p>In theory you can try and convert all Magento 2 MySQL message queues to AMQP RabbitMQ message queues. If you do this you will also probably want to create your own external consumers to process RabbitMQ message queues more efficiently.</p>
<p>Keep in mind that if you create external message queue consumers you should ensure that the consumer processes are always running. There are a few ways to accomplish this for example by using a <a href="http://supervisord.org/" rel="noopener" target="_blank">supervisord </a>process control system. If you are working with a Docker environment I recommend creating one or more consumer containers to manage Magento 2 AMQP messages.</p>
<p>You can configure the default Magento 2 <code>cron_runners_runner</code> cron job via <code>env.php</code> settings</p>
<pre class="brush: plain; title: ; notranslate">
    'cron_consumers_runner' =&gt; &#x5B;
        'cron_run' =&gt; true,
        'max_messages' =&gt; 20000,
        'consumers' =&gt; &#x5B;
            'consumer1',
            'consumer2',
        ]
    ],
</pre>
<p>Note that if you set <code>cron_run</code> here to <code>false</code> you are completely disabling the default consumer cron job in Magento. If you are using external consumers for some or all message queues <strong>think carefully</strong> before completely disabling this cron job.</p>
<p><em>Note &#8211; during testing I was unable to convert some existing Magento 2.4.2 MySQL queues to AMQP</em></p>
<h1>Docker Consumers and Message Management</h1>
<p>I like to use <a href="https://github.com/gaiterjones/docker-magento2/tree/master/magento2/consumer" rel="noopener" target="_blank">dedicated Docker containers</a> to manage message queue consumer processes in my Magento 2 Docker environment. In theory a container should manage a single consumer, in practice it can be easier to run multiple consumers in one container. The container needs to know which consumers to start, and also needs to monitor consumer processes to ensure that they remain running.</p>
<p>To manage this process and make it easier to convert multiple message queues from MySQL db to AMQP I created a <a href="https://github.com/gaiterjones/Magento2_MessageManager" rel="noopener" target="_blank">Message Manager module</a>.</p>
<p>This module allows you to convert some or all queues to AMQP, automatically updating the <code>env.php</code> settings to configure the changes required for each module. The module also feeds data to my Docker container telling the container which consumer processes it should manage.</p>
<p>After installing the module you can display all existing message consumers with:</p>
<p><code>bin/magento messagemanager:getconsumers</code></p>
<p>This will return an array of consumers showing the queue name and the current connection method &#8211; <strong>db</strong> for MySQL, &#8211; <strong>amqp</strong> for RabbitMQ AMQP.</p>
<p>To convert specific queues to AMQP you can define a whitelist in <code>Gaiterjones\MessageManager\Helper\Data</code></p>
<pre class="brush: php; title: ; notranslate">
    public function whitelist(): array
    {
        return array(
            'gaiterjones_message_manager',
            'product_action_attribute.update'
        );
    }
</pre>
<p>Here I am specifying two queues that I want to use with RabbitMQ AMQP. I know <code>gaiterjones_message_manager</code> is already configured for AMQP and I want to convert <code>product_action_attribute.update</code> from MySQL to AMQP.</p>
<p>To do this I can use the getconfig command. First check your current AMQP config with <code>bin/magento messagemanager:getconfig</code> ensure that your RabbitMQ server is configured.</p>
<pre class="brush: php; title: ; notranslate">
    &#x5B;amqp] =&gt; Array
        (
            &#x5B;host] =&gt; magento2_rabbitmq_1
            &#x5B;port] =&gt; 5672
            &#x5B;user] =&gt; blah
            &#x5B;password] =&gt; blah
            &#x5B;virtualhost] =&gt; /
        )
</pre>
<p>Next display the configuration required to convert your whitelisted queues to AMQP</p>
<p><code>bin/magento messagemanager:getconfig --buildconfig --whitelist</code></p>
<p>(To display the configuration for all MySQL configured queues use <code>bin/magento messagemanager:getconfig --buildconfig</code>)</p>
<p>After reviewing the configuration use the <code>saveconfig</code> switch to save this configuration to <code>env.php</code> :</p>
<p><code>bin/magento messagemanager:getconfig --buildconfig --whitelist --saveconfig</code></p>
<p><strong>Make sure you backup</strong> <code>env.php</code> before running this command!</p>
<p>After changing the config run <code>setup:upgrade</code> to reconfigure the module queues. If the queue config creates an error restore your <code>env.php</code> settings and run <code>setup:upgrade</code> again to restore the configuration.</p>
<p>Now you should see the converted queues in RabbitMQ admin.</p>
<figure id="attachment_2393" aria-describedby="caption-attachment-2393" style="width: 600px" class="wp-caption aligncenter"><img decoding="async" src="https://blog.gaiterjones.com/wp-content/uploads/2021/02/mq_2.jpg" alt="MySQL queues converted to AMQP and visible in RabbitMQ" width="600" height="94" class="size-full wp-image-2393" srcset="https://blog.gaiterjones.com/wp-content/uploads/2021/02/mq_2.jpg 600w, https://blog.gaiterjones.com/wp-content/uploads/2021/02/mq_2-440x69.jpg 440w, https://blog.gaiterjones.com/wp-content/uploads/2021/02/mq_2-550x86.jpg 550w" sizes="(max-width: 600px) 100vw, 600px" /><figcaption id="caption-attachment-2393" class="wp-caption-text">MySQL queues converted to AMQP and visible in RabbitMQ</figcaption></figure>
<p>The <code>gaiterjones_message_manager</code> queue is installed with the module, to test RabbitMQ is working use the test queue command <code>bin/magento messagemanager:testqueue</code></p>
<p>You should see a new message created in RabbitMQ.</p>
<figure id="attachment_2394" aria-describedby="caption-attachment-2394" style="width: 600px" class="wp-caption aligncenter"><img decoding="async" src="https://blog.gaiterjones.com/wp-content/uploads/2021/02/mq_3.jpg" alt="RabbitMQ Message Queue Test" width="600" height="394" class="size-full wp-image-2394" srcset="https://blog.gaiterjones.com/wp-content/uploads/2021/02/mq_3.jpg 600w, https://blog.gaiterjones.com/wp-content/uploads/2021/02/mq_3-440x289.jpg 440w, https://blog.gaiterjones.com/wp-content/uploads/2021/02/mq_3-550x361.jpg 550w" sizes="(max-width: 600px) 100vw, 600px" /><figcaption id="caption-attachment-2394" class="wp-caption-text">RabbitMQ Message Queue Test</figcaption></figure>
<h2>Summary</h2>
<p>It is very likely that future versions of Magento 2 will stop using MySQL as a messaging broker. In the same way that Search was moved to Elasticsearch we may have to use RabbitMQ in the future for all Magento async messaging.</p>
<p>Message queues are cool! If you are building production Magento 2 sites in a Docker environment it makes sense to start using RabbitMQ and external consumers now.</p>
<h2>More Reading</h2>
<p>In conclusion I recommend reading through the official documentation for more information on this subject.</p>
<ul>
<li><a href="https://devdocs.magento.com/guides/v2.4/config-guide/mq/manage-message-queues.html#start-message-queue-consumers" rel="noopener" target="_blank">Manage Message Queues</a></li>
<li><a href="https://devdocs.magento.com/guides/v2.4/config-guide/mq/rabbitmq-overview.html" rel="noopener" target="_blank">Message Queues Overview</a></li>
<li><a href="https://devdocs.magento.com/guides/v2.4/config-guide/prod/config-reference-envphp.html#consumers_wait_for_messages" rel="noopener" target="_blank">consumers_wait_for_messages</a></li>
<li><a href="https://devdocs.magento.com/guides/v2.4/extension-dev-guide/message-queues/message-queues.html" rel="noopener" target="_blank">Message Queues</a></li>
</ul>
<h4>Credits</h4>
<p>Thanks to <a href="https://magento.stackexchange.com/users/35330/diana-botean" rel="noopener" target="_blank">Diana Botean</a> for her helpful comments.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.gaiterjones.com/magento-2-asynchronous-message-queue-management/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
