I am working in a Magento 2.3 installation with avarage cart size of 100-150 lines. Getting the visible cart items from Quote is slower over time ( as products count rises )
I've search thought Magento core and i've found that the delay is caused when it tries to get the Quote from the database (?)
in $quote = $this->quoteRepository->getActive($this->getQuoteId());
public function getQuote()
{
$this->_eventManager->dispatch('custom_quote_process', ['checkout_session' => $this]);
if ($this->_quote === null) {
$quote = $this->quoteFactory->create();
if ($this->getQuoteId()) {
try {
if ($this->_loadInactive) {
$quote = $this->quoteRepository->get($this->getQuoteId());
} else {
$quote = $this->quoteRepository->getActive($this->getQuoteId());
}
/**
* If current currency code of quote is not equal current currency code of store,
* need recalculate totals of quote. It is possible if customer use currency switcher or
* store switcher.
*/
if ($quote->getQuoteCurrencyCode() != $this->_storeManager->getStore()->getCurrentCurrencyCode()) {
$quote->setStore($this->_storeManager->getStore());
$this->quoteRepository->save($quote->collectTotals());
/*
* We mast to create new quote object, because collectTotals()
* can to create links with other objects.
*/
$quote = $this->quoteRepository->get($this->getQuoteId());
}
} catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
$this->setQuoteId(null);
}
}
if (!$this->getQuoteId()) {
if ($this->_customerSession->isLoggedIn() || $this->_customer) {
$customerId = $this->_customer
? $this->_customer->getId()
: $this->_customerSession->getCustomerId();
try {
$quote = $this->quoteRepository->getActiveForCustomer($customerId);
$this->setQuoteId($quote->getId());
} catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
}
} else {
$quote->setIsCheckoutCart(true);
$this->_eventManager->dispatch('checkout_quote_init', ['quote' => $quote]);
}
}
if ($this->_customer) {
$quote->setCustomer($this->_customer);
} elseif ($this->_customerSession->isLoggedIn()) {
$quote->setCustomer($this->customerRepository->getById($this->_customerSession->getCustomerId()));
}
$quote->setStore($this->_storeManager->getStore());
$this->_quote = $quote;
}
if (!$this->isQuoteMasked() && !$this->_customerSession->isLoggedIn() && $this->getQuoteId()) {
$quoteId = $this->getQuoteId();
/** @var $quoteIdMask \Magento\Quote\Model\QuoteIdMask */
$quoteIdMask = $this->quoteIdMaskFactory->create()->load($quoteId, 'quote_id');
if ($quoteIdMask->getMaskedId() === null) {
$quoteIdMask->setQuoteId($quoteId)->save();
}
$this->setIsQuoteMasked(true);
}
$remoteAddress = $this->_remoteAddress->getRemoteAddress();
if ($remoteAddress) {
$this->_quote->setRemoteIp($remoteAddress);
$xForwardIp = $this->request->getServer('HTTP_X_FORWARDED_FOR');
$this->_quote->setXForwardedFor($xForwardIp);
}
return $this->_quote;
}
The delay is on average about 15-25 seconds. Is there a way to store this kind of data in a caching storage like Redis ? I've already set Redis as a storage cache with no luck.
Is anyone else experiencing this kind of issue? Magento Changelog claims that carts should be fine when containing about 300 lines
https://devdocs.magento.com/guides/v2.2/release-notes/ReleaseNotes2.2.0CE.html
The project runs on a dedicated server with 32gb of RAM and 8 Cores XEON Cpu
UPDATE
After some more investigation i've found that the delay is on Quote.php line 1380-1391
public function getItemsCollection($useCache = false)
{
if ($this->hasItemsCollection()) {
return $this->getData('items_collection');
}
if (null === $this->_items) {
$this->_items = $this->_quoteItemCollectionFactory->create();
$this->extensionAttributesJoinProcessor->process($this->_items);
$this->_items->setQuote($this);
}
return $this->_items;
}
The weird thing is that there isn't any traffic on Redis CLI monitor when requesting this collection, shouldn't this kind of data be stored in Redis?
UPDATE 2
There seems to be a "plugin" or something around getItemsCollection function. I've stopped execution in it and the response was immediate, if i let it returns the $this->items is shows the delay. Tried to use xdebug in order to find what causes the delay with no luck. Xdebug followed execution until Collection.php where i lost track. Mysql profiler showed around 1500 queries running in cart page ( i think this is a huge number ) although none of them lasted longer than ~5ms ( there where some around 15ms ).
So i've installed a fresh magento installation with luna theme and imported the sample products using composer. The new vm has MySql 5.7, PHP-FPM 7.2 and redis. Enabled production mode, all caches except page_cache and set the deafult cache to redis Added 46 items in cart and the result for just the Document load was ~13s
I can't accept that Magento can't handle this kind of cart size. This time is not acceptable from the end-users.
No clue from where to start searching.
UPDATE 3
Upgraded server ( CPU + more ram ) with no results. Any idea on how to cache the whole quote ? There seems to be no way of serializing the Object due to Closures. I am trying to figure if a short caching in redis ( or a longer one for the checkout page only ) makes a difference.
Already tried serialize, json_encode and base_64 for the Quote