magento / magento2

Prior to making any Submission(s), you must sign an Adobe Contributor License Agreement, available here at: https://opensource.adobe.com/cla.html. All Submissions you make to Adobe Inc. and its affiliates, assigns and subsidiaries (collectively “Adobe”) are subject to the terms of the Adobe Contributor License Agreement.
http://www.magento.com
Open Software License 3.0
11.53k stars 9.31k forks source link

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

Closed IvanChepurnyi closed 3 years ago

IvanChepurnyi commented 4 years ago

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.

https://github.com/magento/magento2/issues/25862#issuecomment-602170384 https://github.com/magento/magento2/issues/25862#issuecomment-665347649

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;
m2-assistant[bot] commented 4 years ago

Hi @IvanChepurnyi. Thank you for your report. To help us process this issue please make sure that you provided the following information:

Please make sure that the issue is reproducible on the vanilla Magento instance following Steps to reproduce. To deploy vanilla Magento instance on our environment, please, add a comment to the issue:

@magento give me 2.3-develop instance - upcoming 2.3.x release

For more details, please, review the Magento Contributor Assistant documentation.

@IvanChepurnyi do you confirm that you were able to reproduce the issue on vanilla Magento instance following steps to reproduce?


rhoerr commented 4 years ago

This same code also wreaks havoc on error handling, and the ability to handle errors from code when they do occur.

Related issue: https://github.com/magento/magento2/issues/18752#issuecomment-522027742

m2-assistant[bot] commented 4 years ago

Hi @engcom-Charlie. Thank you for working on this issue. In order to make sure that issue has enough information and ready for development, please read and check the following instruction: :point_down:

magento-engcom-team commented 4 years ago

:white_check_mark: Confirmed by @engcom-Charlie Thank you for verifying the issue. Based on the provided information internal tickets MC-29335 were created

Issue Available: @engcom-Charlie, You will be automatically unassigned. Contributors/Maintainers can claim this issue to continue. To reclaim and continue work, reassign the ticket to yourself.

PascalBrouwers commented 4 years ago

Interested if this will also fix my issues with ghost orders who have an order id in PSP

m2-assistant[bot] commented 4 years ago

Hi @sdzhepa. Thank you for working on this issue. Looks like this issue is already verified and confirmed. But if you want to validate it one more time, please, go though the following instruction:


sdzhepa commented 4 years ago

Hello @IvanChepurnyi @PascalBrouwers @rhoerr

The internal Magento team is working on this issue right now. Fix is almost done in the scope of internal Jira tickets MC-29335 and MC-29206. Currently, all development work is done and its on the QA stage.

I will keep updating this Issue with commits as soon as changes will be pushed to the public magento/magento2 repo

convenient commented 4 years ago

Very interesting. I wonder if this could cause https://github.com/magento/magento2/issues/15427#issuecomment-456399516 where I saw a deadlock in paypal express.

IvanChepurnyi commented 4 years ago

@convenient This issue might have caused dozens of adverse effects since the introduction of transactions in guest order placement API. Your deadlock most probably a combination of both factors, this issue and REPEATABLE-READ transaction mode in MySQL when the table gets locked for inserting new records if any transaction has a locking gap in the index for new increment value. I use for all merchants READ-COMMITED mode that does not have any gap locks, so even if such problem exists inserting to table is possible.

convenient commented 4 years ago

Thank you @IvanChepurnyi I will look into the READ-COMMITTED mode.

ccrothers commented 4 years ago

@sdzhepa Any updates? Noticed this fix didn't make it into January's 2.3.4 release. Is this feature on track to be included in the April 28th release of 2.3.5 M2 Commerce? https://devdocs.magento.com/release/

sdzhepa commented 4 years ago

Hello @ccrothers

Internal Jira ticket related to 2.4 MC-29335 still in open status

sdzhepa commented 4 years ago

FYI: @ccrothers @IvanChepurnyi @convenient @PascalBrouwers @rhoerr

cc: @naydav @andrewbess

One more update After investigation of all internal Jira tickets related to this bug I found that it was fixed in the scope of other Jira tasks. Here is a small summary:

May I ask to confirm:

IvanChepurnyi commented 4 years ago

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.

ccrothers commented 4 years ago

I've also seen (since at least 2.3.2, but likely in earlier versions too) deadlock wait timeouts on inventory_source_item under heavy loads. Not sure if that is related, but could be. Very likely a ticket somewhere for that already.

angelomaragna commented 4 years ago

The transaction management in the guest orders payments has always been a huge pain in the ... since we discovered it too.

In my opinion, you can't simply wrap a whole placeOrder with a transaction where you allow for any third party extension to run on observers and roll back in case anything goes wrong allowing an ecommerce platform to fail in such a spectacular way.

Using lots of thirdparty extensions, I've seen many different situation where an undetected conditions in some code led to a _isRolledBack set to true in Magento\Framework\DB\Adapter\Pdo\Mysql, all subsequent tasks blocked and the previous ones to be reverted back.

No doubt for me this is a design bug that went hugely unnoticed.

The quickets "patches" are to fix all third party extensions causing that, or in the case of lots of deadlocks appearing to scale up platform specs.

Another option, is to temporarily dump all data to disk (dirty option, but as a bridge because of locked writing to database) when a rollback happens and subsequently analyse the reason of failure. All failed payment attempts on guest carts are treated in the same way by Magento, so, the reason in the exception at Magento\Checkout\Model\GuestPaymentInformationManagement.

But, again, "patches" for a problem that is still there.

PascalBrouwers commented 4 years ago

Release notes says this is in 2.4. Is that correct?

sdzhepa commented 4 years ago

Hello @PascalBrouwers

I checked the internal jira ticket and based on them this issue has been fixed by Magento team

Also, today were release Magento versions 2.4.0 and 2.3.5p2 so fixes should be available in both of them.

Could you please confirm that the initial issue has been fixed and we can close this public ticket?

IvanChepurnyi commented 4 years ago

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.

As soon as you fix this one

ravimagedelight commented 4 years ago

Is this already fixed for the 2.3.x version?

Also is there any way to retrieve those missing guest orders? I can retrieve logged in customers' orders since they are logged in the quote table.

sodhancha commented 4 years ago

@IvanChepurnyi are there any updates on this issue ? Is this issue fixed / not-fixed ?

sodhancha commented 4 years ago

@sdzhepa this issue has left us with a big hole in our pocket. It's happening not just for guest users but for all users with all payment gateways

matthijsburki commented 4 years ago

L.s., Ik ben 21 otober niet aanwezig en niet in staat mijn e-mail te beantwoorden. Domderdag 22 oktober zal ik wanneer nodig op het verstuurde bericht reageren. Voor dringende zaken kan er contact worden opgenomen met mijn collega Patricia Vieveen per e-mail patricia@cream.nl of telefoon 010-7536090.

I’m not in the office on Wednesday 21th of October. Your e-mail will not be forwarded. I’ll respond to it when I’m back at the office on the 22th. You can contact my coworker Patricia Vieveen for urgent matters per e-mail patricia@cream.nl or phone +31 10 7536090.

Matthijs Burki

sskharate commented 4 years ago

Client reported this same issue. They are on 2.3.5-p1 with Magento Cloud.

I have checked this commit https://github.com/magento/magento2/commit/43e41fac06019d12e955d521cd9034b5954cb0d9 looks like the code is already in 2.3.5 but the issue is not fixed.

Do we have any fix for this? Thanks.

o-iegorov commented 4 years ago

Internal team start working on this issue

sodhancha commented 3 years ago

@engcom-Charlie what is the timeline for this release ?

viktym commented 3 years ago

@sodhancha The internal team resolved the issue - async processing for the coupon/rule usage was implemented. PR with the solution will be delivered in the 2.4-develop branch during the next 2 weeks.

o-iegorov commented 3 years ago

The changes already merged into 2.4-develop. Commit id: a18bfe065517d485aef15c3ac05456bccb560af8

sdzhepa commented 3 years ago

Due to the comments above issue is fixed and delivered Closed as fixed

johnorourke commented 3 years ago

This also fixes #18752 - exception thrown during payment capture causes a poor error for the user and the exception log contains "Rolled back transaction has not been completed correctly"

zcuric commented 3 years ago

The changes already merged into 2.4-develop. Commit id: a18bfe0

Can this be extracted to a plugin for the time being? I don't have very much experience with plugin development.

hubertus2017 commented 3 years ago

..lost 3% of payments…and tons of hours… will this fix be implemented in Magento 2.4.2? i cant find it in the release notes.

to be clear: I do have magento 2.4.1

Remark from Gene commerce, who are responsible for the bundlked braintree plugin:

We have seen numbers of merchants who faced the same issue where the Orders do not appear in Magento but they appear in Braintree Transaction. We had spent numbers of hours on this issue last year and at the end, it was found that this issue was from Magento end. We contacted Magento and they informed that this issue was fixed and fix is available from Magento 2.4 onwards.

zcuric commented 3 years ago

@hubertus2017 05.02.2020. is release day for 2.4.2. Hope this get's fixed, we are having a lot of problems because of this.

sdzhepa commented 3 years ago

Hello @zcuric @hubertus2017

jFYI: https://github.com/magento/magento2/issues/31967#issuecomment-774107176

based on internal Jira ticket MC-29335 target version is 2.4.3

zcuric commented 3 years ago

Hello @zcuric @hubertus2017

jFYI: https://github.com/magento/magento2/issues/31967#issuecomment-774107176

based on internal Jira ticket MC-29335 target version is 2.4.3

Oh boy, so not in 2.4.2? Man, this is disappointing. Can some please make a patch or extension that fixes this?

zcuric commented 3 years ago

@sdzhepa has this landed in 2.4.2?

magento-quality-patches commented 3 years ago

The patch solving a similar issue is available in Magento Quality Patches package (MQP)

Patch MDVA-31519: Fixes the issue where missing paid orders and lock wait timeouts in Guest Checkout.

Compatible versions Magento OpenSource/Commerce/Commerce Cloud 2.3.5, 2.3.5-p1, 2.3.5-p2

:warning: We strongly recommend testing all patches in a staging or development environment before deploying to production.

Applying a patch - Magento OpenSource/Commerce

  1. $ composer require magento/quality-patches
  2. $ ./vendor/bin/magento-patches apply MDVA-31519

See MQP Magento Commerce documentation

Applying a patch - Magento Commerce Cloud See MQP Magento Commerce Cloud documentation

Patch Details https://support.magento.com/hc/en-us/articles/360055441412

magento-quality-patches commented 3 years ago

@zcuric ^^^

sodhancha commented 3 years ago

This is not compatible with EE 2.4.0 Please provide a patch which is compatible with EE 2.4.0

On Thu, Feb 11, 2021 at 4:12 AM Magento Quality Patches < notifications@github.com> wrote:

@zcuric https://github.com/zcuric ^^^

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/magento/magento2/issues/25862#issuecomment-777077523, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAIA3O7RJ76UAYW4GHHYKQTS6MB3VANCNFSM4JTGWT7A .

-- Regards, Sodhan Manandhar

zcuric commented 3 years ago

This is not compatible with EE 2.4.0 Please provide a patch which is compatible with EE 2.4.0 On Thu, Feb 11, 2021 at 4:12 AM Magento Quality Patches < @.***> wrote: @zcuric https://github.com/zcuric ^^^ — You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub <#25862 (comment)>, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAIA3O7RJ76UAYW4GHHYKQTS6MB3VANCNFSM4JTGWT7A . -- Regards, Sodhan Manandhar

@magento-quality-patches

paragpadsumbiya commented 2 years ago

@zcuric We have faced same issue with our client as well and as we can see we didn't found issue in normal days but when there was a sale and there was lot of traffic on site then we faces this issue that Authorize.net have paid orders but we didn't found those orders in system . So is there any solution for this ?

sodhancha commented 2 years ago

Opening this again. This issue has occured for customers who are not GUEST

LillyDrogerie commented 2 years ago

Confirming that this happens relatively often on EE 2.4.2 as well. The payment processor finish the transaction, but the quote for the given order doesn't exists (anymore?), thus the order creation cannot be finished, leading to the customer being charged but order never created thus cannot be fulfilled. Its annoying because there is no specific rule to debug, it can happen with registered users as well with guest accounts, but no clear reason why exactly it happens. Not to mention that it ruins the reputation of the website...

chriswatt commented 1 year ago

Experiencing the same problem on Magento 2.4.4 - Customer placed an order, our payment provider (Stripe) charged the customer. The payment references the Magento order number, however that order number doesn't exist

image

image

WakizashiYoshikawa commented 1 year ago

We have managed to narrow it down to the point of basically a racing condition... You can relatively easily reproduce it.

  1. set the stock of the product to 1
  2. Add it to cart and go to the checkout
  3. Emulate the slow internet connection and initiate electronic payment (Stripe, paypal etc)
  4. Start checkout payment, In our case user is transferred to the 3rd party payment gateway with increment_id of the Magento order so we had plenty of time to finish step 5
  5. Meanwhile drop the stock to 0 in magento backend (basically emulate racing condition)
  6. Finalize the payment on Stripe/PayPal etc
  7. The payment will be processed by Stripe/PP, the callback will be sent, but Magento will fail to create the order since the stock is 0

Hope it helps someone...