diff --git a/vendor/magento/module-sales/Cron/CleanExpiredQuotes.php b/vendor/magento/module-sales/Cron/CleanExpiredQuotes.php
index 978aec1b79e..785d03b9b56 100644
--- a/vendor/magento/module-sales/Cron/CleanExpiredQuotes.php
+++ b/vendor/magento/module-sales/Cron/CleanExpiredQuotes.php
@@ -9,6 +9,7 @@ use Exception;
use Magento\Quote\Model\QuoteRepository;
use Magento\Quote\Model\ResourceModel\Quote\Collection as QuoteCollection;
use Magento\Sales\Model\ResourceModel\Collection\ExpiredQuotesCollection;
+use Magento\Store\Api\Data\StoreInterface;
use Magento\Store\Model\StoreManagerInterface;
use Psr\Log\LoggerInterface;
@@ -17,6 +18,11 @@ use Psr\Log\LoggerInterface;
*/
class CleanExpiredQuotes
{
+ /**
+ * Default number of quotes processed per iteration.
+ */
+ private const DEFAULT_BATCH_SIZE = 5000;
+
/**
* @var ExpiredQuotesCollection
*/
@@ -37,22 +43,30 @@ class CleanExpiredQuotes
*/
private $logger;
+ /**
+ * @var int
+ */
+ private $batchSize;
+
/**
* @param StoreManagerInterface $storeManager
* @param ExpiredQuotesCollection $expiredQuotesCollection
* @param QuoteRepository $quoteRepository
* @param LoggerInterface $logger
+ * @param int $batchSize
*/
public function __construct(
StoreManagerInterface $storeManager,
ExpiredQuotesCollection $expiredQuotesCollection,
QuoteRepository $quoteRepository,
- LoggerInterface $logger
+ LoggerInterface $logger,
+ int $batchSize = self::DEFAULT_BATCH_SIZE
) {
$this->storeManager = $storeManager;
$this->expiredQuotesCollection = $expiredQuotesCollection;
$this->quoteRepository = $quoteRepository;
$this->logger = $logger;
+ $this->batchSize = $batchSize > 0 ? $batchSize : self::DEFAULT_BATCH_SIZE;
}
/**
@@ -64,29 +78,44 @@ class CleanExpiredQuotes
{
$stores = $this->storeManager->getStores(true);
foreach ($stores as $store) {
+ $this->deleteExpiredQuotesInBatches($store);
+ }
+ }
+
+ /**
+ * Deletes expired quotes in keyset batches for a single store.
+ *
+ * @param StoreInterface $store
+ */
+ private function deleteExpiredQuotesInBatches(StoreInterface $store): void
+ {
+ $lastProcessedId = 0;
+ do {
/** @var $quoteCollection QuoteCollection */
$quoteCollection = $this->expiredQuotesCollection->getExpiredQuotes($store);
- $quoteCollection->setPageSize(50);
-
- // Last page returns 1 even when we don't have any results
- $lastPage = $quoteCollection->getSize() ? $quoteCollection->getLastPageNumber() : 0;
-
- for ($currentPage = $lastPage; $currentPage >= 1; $currentPage--) {
- $quoteCollection->setCurPage($currentPage);
-
- $this->deleteQuotes($quoteCollection);
- }
- }
+ $quoteCollection->addFieldToSelect('entity_id');
+ $quoteCollection->addFieldToFilter('main_table.entity_id', ['gt' => $lastProcessedId]);
+ $quoteCollection->setOrder('main_table.entity_id', 'ASC');
+ $quoteCollection->setPageSize($this->batchSize);
+ $quoteCollection->setCurPage(1);
+ $quoteCollection->getSelect()->distinct(true);
+ $processedCount = $this->deleteQuotes($quoteCollection, $lastProcessedId);
+ } while ($processedCount === $this->batchSize);
}
/**
- * Deletes all quotes in collection
+ * Deletes all quotes in a collection and advances last processed id.
*
* @param QuoteCollection $quoteCollection
+ * @param int $lastProcessedId
+ * @return int
*/
- private function deleteQuotes(QuoteCollection $quoteCollection): void
+ private function deleteQuotes(QuoteCollection $quoteCollection, int &$lastProcessedId): int
{
+ $processedCount = 0;
foreach ($quoteCollection as $quote) {
+ $processedCount++;
+ $lastProcessedId = (int)$quote->getId();
try {
$this->quoteRepository->delete($quote);
} catch (Exception $e) {
@@ -100,5 +129,6 @@ class CleanExpiredQuotes
}
$quoteCollection->clear();
+ return $processedCount;
}
}
diff --git a/vendor/magento/module-sales/etc/di.xml b/vendor/magento/module-sales/etc/di.xml
index a0bc3d7dc8b..28dcbf91d5c 100644
--- a/vendor/magento/module-sales/etc/di.xml
+++ b/vendor/magento/module-sales/etc/di.xml
@@ -326,7 +326,11 @@
SalesCreditmemoIndexGridAsyncInsert
-
+
+
+ 5000
+
+
Magento\Sales\Model\Order\Email\Sender\OrderSender