diff --git a/vendor/magento/module-quote/Model/CustomerCartMutex.php b/vendor/magento/module-quote/Model/CustomerCartMutex.php new file mode 100644 index 0000000000000..07853506920ec --- /dev/null +++ b/vendor/magento/module-quote/Model/CustomerCartMutex.php @@ -0,0 +1,62 @@ +storeManager->getStore($storeId)->getWebsiteId(); + $lockName = self::LOCK_PREFIX . $customerId . '_' . $websiteId; + + if (!$this->lockManager->lock($lockName, $this->lockWaitTimeout)) { + $this->logger->critical( + 'The customer cart is locked, the request has been aborted.' + . ' Customer ID: ' . $customerId . ', Store ID: ' . $storeId + ); + throw new CustomerCartMutexException( + __('The customer cart is locked for processing. Please try again later.') + ); + } + + try { + return $callable(...$args); + } finally { + $this->lockManager->unlock($lockName); + } + } +} diff --git a/vendor/magento/module-quote/Model/CustomerCartMutexException.php b/vendor/magento/module-quote/Model/CustomerCartMutexException.php new file mode 100644 index 0000000000000..6271116123c4a --- /dev/null +++ b/vendor/magento/module-quote/Model/CustomerCartMutexException.php @@ -0,0 +1,16 @@ +eventManager = $eventManager; $this->submitQuoteValidator = $submitQuoteValidator; @@ -271,6 +279,8 @@ public function __construct( ->get(RemoteAddress::class); $this->cartMutex = $cartMutex ?? ObjectManager::getInstance()->get(CartMutexInterface::class); + $this->customerCartMutex = $customerCartMutex + ?? ObjectManager::getInstance()->get(CustomerCartMutexInterface::class); } /** @@ -299,7 +309,30 @@ public function createEmptyCart() */ public function createEmptyCartForCustomer($customerId) { - $storeId = $this->storeManager->getStore()->getStoreId(); + $store = $this->storeManager->getStore(); + try { + return $this->customerCartMutex->execute( + (int)$customerId, + (int)$store->getStoreId(), + \Closure::fromCallable([$this, 'createEmptyCartForCustomerRun']), + [(int)$customerId, (int)$store->getStoreId()] + ); + } catch (CustomerCartMutexException $e) { + throw new CouldNotSaveException(__("The quote can't be created."), $e); + } + } + + /** + * Creates an empty cart for the customer, called within the customer cart mutex. + * + * @param int $customerId + * @param int $storeId + * @return int + * @throws CouldNotSaveException + * @SuppressWarnings(PHPMD.UnusedPrivateMethod) + */ + private function createEmptyCartForCustomerRun(int $customerId, int $storeId): int + { $quote = $this->createCustomerCart($customerId, $storeId); $this->_prepareCustomerQuote($quote); diff --git a/vendor/magento/module-quote/etc/di.xml b/vendor/magento/module-quote/etc/di.xml index cd46d9e6314c5..65eb08029e678 100644 --- a/vendor/magento/module-quote/etc/di.xml +++ b/vendor/magento/module-quote/etc/di.xml @@ -49,6 +49,7 @@ +