magento / magento2

Prior to making any Submission(s), you must sign an Adobe Contributor License Agreement, available here at: https://opensource.adobe.com/cla.html. All Submissions you make to Adobe Inc. and its affiliates, assigns and subsidiaries (collectively “Adobe”) are subject to the terms of the Adobe Contributor License Agreement.
http://www.magento.com
Open Software License 3.0
11.49k stars 9.3k forks source link

Message Queue consumer issue : context is not reset between messages #37870

Open Nuranto opened 1 year ago

Nuranto commented 1 year ago

Preconditions and environment

Steps to reproduce

  1. Create a command test:publish_message that publish a message on a queue
  2. Create a consumer that loads and display a product stock qty (via stock registry), and logs it. (initial qty = 100)
  3. Launch the consumer
  4. Run the test:publish_message
  5. Edit the qty of the product on backend (qty : 200)
  6. Run the test:publish_message
  7. Check consumer's logs

Expected result

Logs should display :

100
200

Actual result

Logs display :

100
100

Additional information

This is because both messages are running in the same environement, without any reset of any kind.

With a high value of --max-messages or with consumers-wait-for-messages a consumer can run for days before restarting. This can have very bad consequences for some consumers.

I guess the easiest and safest solution is to run the message execution in a new process. But maybe it could also do the trick to - somehow - reset ObjectManager between each messages (But I'm afraid about memory consumption with that).

Workaround :

(with --consumers-wait-for-messages=1)

while true; do bin/magento queue:consumers:start --max-messages=1 -vvv consumer.name; done

This is a lot slower :/ but it solves the issue while waiting for a fix.

Release note

No response

Triage and priority

m2-assistant[bot] commented 1 year ago

Hi @Nuranto. Thank you for your report. To speed up processing of this issue, make sure that the issue is reproducible on the vanilla Magento instance following Steps to reproduce. To deploy vanilla Magento instance on our environment, Add a comment to the issue:

m2-assistant[bot] commented 1 year ago

Hi @engcom-Hotel. Thank you for working on this issue. In order to make sure that issue has enough information and ready for development, please read and check the following instruction: :point_down:

engcom-Hotel commented 1 year ago

Hello @Nuranto,

Thanks for the report and collaboration!

We have tried to reproduce the issue in Magento 2.4-develop branch and the issue is reproducible for us. We have used the below codebase to get to quantity of the product in consumer:

            $productSku = 'SimpleProduct1';
            $product = $this->productRepository->get($productSku);
            $stockItem = $this->stockRegistry->getStockItem($product->getId());
            $quantity = $stockItem->getQty();
            $message = $quantity . PHP_EOL;
            file_put_contents('CUSTOM_PATH/log.txt', $message, FILE_APPEND);

It is always returning the initial stock value even after reindexing and cache clear:

bin/magento indexer:reindex && bin/magento c:f

Hence confirming the issue.

Thanks

github-jira-sync-bot commented 1 year ago

:white_check_mark: Jira issue https://jira.corp.adobe.com/browse/AC-9549 is successfully created for this GitHub issue.

m2-assistant[bot] commented 1 year ago

:white_check_mark: Confirmed by @engcom-Hotel. Thank you for verifying the issue.
Issue Available: @engcom-Hotel, You will be automatically unassigned. Contributors/Maintainers can claim this issue to continue. To reclaim and continue work, reassign the ticket to yourself.

abhishek-omnia commented 6 months ago

@engcom-Hotel any updates regarding these issue i am also facing this issue i am not able to find solution

gorbunovav commented 1 month ago

Magento often relies on a very basic caching approach, where loaded entities are stored in an instance's private field. However, unlike with HTTP requests, the context doesn't reset while a consumer is running. This means that message handlers remain completely unaware of any external changes, including those from other consumers running in separate processes.

The potential for data inconsistencies here is enormous.

And you don't need the consumer to run for a long time - just enough to have an external data change between two messages processing.

AndresInSpace commented 3 weeks ago

Magento often relies on a very basic caching approach, where loaded entities are stored in an instance's private field. However, unlike with HTTP requests, the context doesn't reset while a consumer is running. This means that message handlers remain completely unaware of any external changes, including those from other consumers running in separate processes.

The potential for data inconsistencies here is enormous.

And you don't need the consumer to run for a long time - just enough to have an external data change between two messages processing.

I haven't dug into the underlying code yet, but it sounds like you are saying once the consumer messages model loads a product the product model is cached in the instance (as magento does) and thus subsequent messages loading same product id are serving from instance cache (memory) rather than a new db query result?