Description
In the Klaviyo extension, we have a plugin that adds a masked quote id to quote search API requests. That looks like quite a small plugin that shouldn't cause any performance or functional damage.
In most cases, it works well, but sometimes we see that such request causing eating 100% CPU by the php-fpm, and Gateway Timeout issues after quite a long time 60 seconds.
Here is a link to the plugin in the Klaviyo extension (it uses API class, which is ok):
https://github.com/klaviyo/magento2-klaviyo/blob/3.0.5/Plugin/Api/CartSearchRepository.php
Detailed investigation showed that issue is coming from the following line:
magento2/app/code/Magento/Quote/Model/QuoteIdToMaskedQuoteId.php
Lines 50 to 53 in afa2169
-> it goes to
-> and then to
magento2/app/code/Magento/Quote/Model/Quote.php
Lines 912 to 917 in 7c6b636
Looks pretty small and simple, right? Yes... but... here we have the recollect totals and re-saving quote
magento2/app/code/Magento/Quote/Model/Quote.php
Lines 2461 to 2468 in 7c6b636
In case if the quote has trigger_recollect
= 1:
we running the following code:
magento2/app/code/Magento/Quote/Model/Quote/TotalsCollector.php
Lines 146 to 148 in 7c6b636
This code triggers an event:
magento2/app/code/Magento/Quote/Model/Quote/TotalsCollector.php
Lines 263 to 264 in 7c6b636
That execites an event observer:
magento2/app/code/Magento/SalesRule/etc/events.xml
Lines 30 to 32 in 7c6b636
magento2/app/code/Magento/SalesRule/Observer/CouponCodeValidation.php
Lines 58 to 79 in 7c6b636
That... runs
$this->cartRepository->getList
method... for which we just added a plugin for adding masked quote ids!
As a result - we have an infinite loop.
Preconditions (*)
- Magento 2.3.7 or 2.4-develop
Steps to reproduce (*)
-
Install Klaviyo extension (tested on version 3.0.5)
OR Add a plugin, that adds masked quote id to response for the cart search API, for example:
-
Create Cart Price Rule with coupon (let's give some 10% discount)
-
Add some product to the shopping cart, apply the coupon from step 2
-
Run the following code with and w/o Klaviyo extension:
curl --location --request GET 'https://www.mymagento.com/index.php/rest/default/V1/carts/search?searchCriteria%5Bfilter_groups%5D%5B0%5D%5Bfilters%5D%5B0%5D%5Bfield%5D=updated_at&searchCriteria%5Bfilter_groups%5D%5B0%5D%5Bfilters%5D%5B0%5D%5Bvalue%5D=2021-06-11+11%3A38%3A16&searchCriteria%5Bfilter_groups%5D%5B0%5D%5Bfilters%5D%5B0%5D%5Bcondition_type%5D=gt&searchCriteria%5BsortOrders%5D%5B0%5D%5Bfield%5D=updated_at&searchCriteria%5BsortOrders%5D%5B0%5D%5Bdirection%5D=DESC&searchCriteria%5BcurrentPage%5D=1&searchCriteria%5BpageSize%5D=50' \
--header 'Authorization: Bearer dk6zp483qmck8omd7sov1r3b9is7kxh'
Note: here is documentation on how to get access token https://devdocs.magento.com/guides/v2.4/get-started/authentication/gs-authentication-token.html#request-token
✔ we successfully retrieved the list of carts
- Go to admin, edit the Cart Price Rule that you created in step 2, do the following steps:
- change the coupon code, save the rule
- disable the cart price rule, save it
- Run the code from step 4
Expected result (*)
- You should get the JSON with a list of carts
Actual result (*)
Please provide Severity assessment for the Issue as Reporter. This information will help during Confirmation and Issue triage processes.
- Severity: S0 - Affects critical data or functionality and leaves users without workaround.
- Severity: S1 - Affects critical data or functionality and forces users to employ a workaround.
- Severity: S2 - Affects non-critical data or functionality and forces users to employ a workaround.
- Severity: S3 - Affects non-critical data or functionality and does not force users to employ a workaround.
- Severity: S4 - Affects aesthetics, professional look and feel, “quality” or “usability”.