Skip to content

Missing paid orders and lock wait timeouts in Guest Checkout #25862

Closed
@IvanChepurnyi

Description

@IvanChepurnyi

Update on Jul 28 2020
The issue was not completely fixed in internal Jira tickets MC-29335 and MC-29206.

That solution looks like not completely fixes a problem, as sales rule usage update still potentially causes deadlock under high load when a lot of concurrent orders are placed at the same time. The only way to fix this problem is by introducing the append-only event log of sales rule counter adjustment log and using cronjob to update sales rule table.

#25862 (comment)
#25862 (comment)

During peak sales hour, one of my customers lost 400+ Magento orders but had charged credit card transactions at the PSP.

At first, I thought PSP implementation was a reason for missing orders, but after the investigation, it turned out this a result of a pull request being merged 2 years ago in Guest Place Order API endpoint of Magento related to this issue #6363.

That change added beginTransaction() and commit() around the whole place order process involving payment API calls and multi-entity save process ignoring that it results in lock contention on database level for an update of the same row in the same table (sales_rule). Although intentions were good (implementation to fix stock deduction issues), but it introduced huge performance bottleneck and rollbacks complete order history for paid and valid orders if wait-lock happens during the ordering process.

Preconditions (*)

  1. Magento 2.2.4+ or Magento 2.3.0+
  2. Enabled Guest Checkout
  3. Site-wide sales rule like "Free shipping above x amount"

Steps to reproduce (*)

  1. Stress test system with concurrent guest orders involving API payment PSP

Expected result (*)

  1. All paid payment transactions are saved to the database and visible in the admin panel

Actual result (*)

  1. A small fraction of orders is saved in the database while the majority of orders lost because of lock wait timeout.

Workaround

If you are using MSI it is possible to completely remove transactions and make it work in the same way as for logged-in user checkouts. Here is a patch that can be applied for "magento/module-checkout":

Index: Model/GuestPaymentInformationManagement.php
<+>UTF-8
===================================================================
--- Model/GuestPaymentInformationManagement.php	(date 1575083782000)
+++ Model/GuestPaymentInformationManagement.php	(date 1575083782000)
@@ -98,33 +98,20 @@
         \Magento\Quote\Api\Data\PaymentInterface $paymentMethod,
         \Magento\Quote\Api\Data\AddressInterface $billingAddress = null
     ) {
-        $salesConnection = $this->connectionPool->getConnection('sales');
-        $checkoutConnection = $this->connectionPool->getConnection('checkout');
-        $salesConnection->beginTransaction();
-        $checkoutConnection->beginTransaction();
-
-        try {
-            $this->savePaymentInformation($cartId, $email, $paymentMethod, $billingAddress);
-            try {
-                $orderId = $this->cartManagement->placeOrder($cartId);
-            } catch (\Magento\Framework\Exception\LocalizedException $e) {
-                throw new CouldNotSaveException(
-                    __($e->getMessage()),
-                    $e
-                );
-            } catch (\Exception $e) {
-                $this->getLogger()->critical($e);
-                throw new CouldNotSaveException(
+        $this->savePaymentInformation($cartId, $email, $paymentMethod, $billingAddress);
+        try {
+            $orderId = $this->cartManagement->placeOrder($cartId);
+        } catch (\Magento\Framework\Exception\LocalizedException $e) {
+            throw new CouldNotSaveException(
+                __($e->getMessage()),
+                $e
+            );
+        } catch (\Exception $e) {
+            $this->getLogger()->critical($e);
+            throw new CouldNotSaveException(
                     __('An error occurred on the server. Please try to place the order again.'),
-                    $e
-                );
-            }
-            $salesConnection->commit();
-            $checkoutConnection->commit();
-        } catch (\Exception $e) {
-            $salesConnection->rollBack();
-            $checkoutConnection->rollBack();
-            throw $e;
+                $e
+            );
         }

         return $orderId;

Metadata

Metadata

Assignees

No one assigned

    Labels

    CDIssue recommended for the contribution dayComponent: CheckoutFixed in 2.4.xThe issue has been fixed in 2.4-develop branchIssue: Clear DescriptionGate 2 Passed. Manual verification of the issue description passedIssue: ConfirmedGate 3 Passed. Manual verification of the issue completed. Issue is confirmedIssue: Format is validGate 1 Passed. Automatic verification of issue format passedIssue: Ready for WorkGate 4. Acknowledged. Issue is added to backlog and ready for developmentPriority: P2A defect with this priority could have functionality issues which are not to expectations.Progress: doneReproduced on 2.3.xThe issue has been reproduced on latest 2.3 releaseSeverity: S2Major restrictions or short-term circumventions are required until a fix is available.Triage: Dev.ExperienceIssue related to Developer Experience and needs help with Triage to Confirm or Reject itTriage: Performance

    Type

    No type

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions