I'm new to Drupal and have to make a Offsite Payment Gateway. (With Drupal Commerce 2)

It all works - except sometimes it doesn't. 

I believe this is due to a race condition between `onReturn()` and `onNotify()`: In `onNotify()` i set a property on the order and save the order. However, Drupal Commerce seems to automatically save the order in `onReturn()` too (out of my control). I think that sometimes this saving of the order in `onReturn()` will overwrite the change i did to the order in onNotify(), causing the data to be lost, when `onReturn()` and `onNotify()` are being called at almost the same time.

Is there a safe way to do `->setData(...)` on the `$order` in `onNotify()`? (How would you do it?)

Thanks for any help!

\
.

---

**More detailed description of the problem: (This can be skipped)**

The remote payment provider's server sends notification-requests to my server, about the status of the payment, so i have both `onReturn` and `onNotify` in my PaymentGateway class.

Since `onReturn` is not guaranteed to be called (the customer might close the browser, etc, and the provider does not necessarily send him back in my case), but `onNotify` is guaranteed to be called, i create and save my `Payment`-object in `onNotify`, not in `onReturn`, when the payment is complete. \
(This is also what the documentation suggests to do: https://docs.drupalcommerce.org/commerce2/developer-guide/payments/create-payment-gateway/off-site-gateways/handling-ipn)

So my code looks something like this (**very** simplified pseudo-code + validation checks not included here):

	class RedirectCheckout extends OffsitePaymentGatewayBase implements SupportsNotificationsInterface {

	    ...

	    public function onReturn(...) {
	    	$is_order_accepted = ...check if the remote payment provider has accepted the order...
	    	
	    	if (!$is_order_accepted)
	    	    throw new NeedsRedirectException(...)
	    	
	    	// if all is good, do nothing
	    }

	    public function onNotify(...) {

		    /** @var OrderInterface $order */
            $order = ...load the order the notification is about...

            $is_order_accepted = ...check if the remote payment provider has accepted the order...
            if ($is_order_accepted) {
                $payment = $payment_storage->create(...);
                $payment->save();

                $order->setData('transaction_id', $transactionId);
                $order->save(); // <- THIS IS WHAT SOMETIMES IS OVERWRITTEN BY onReturn(), I BELIEVE.
            }
        }
	}

Notice that i need to save some data on the order, when an order is accepted (which is not available when the order is created - only when a payment succeeds). \
(The Drupal Commerce documentation says you "don't need to (and should not)" touch the order, but i have to save some extra data on the order, that other parts on the system expects to be there. Interesting what they mean by "(and should not)"...)


This often works. However, the two `onReturn` and `onNotify` requests from the remote server sometimes arrives at almost the same time, which i believe leads to a race condition. (My current theory)

Unfortunately, even though i'm not doing anything to the order in `onReturn`, commerce seems to still save the order. I belive this can sometimes overwrite the data saved to the order by `onNotify`. Example: 

 - `onReturn` starts running, and loads the order (This is done by the commerce library itself, so i can't do anything about this - or can i?)
 - Now, the notify-request arrives, so `onNotify` starts running, loads and saves the order, and returns.
 - After this, the `onReturn` method returns, gives back control to commerce, which saves the order again - but since it loaded the order-object it BEFORE `onNotify` saved it, it overwrites whatever `onNotify` wrote with old data, when it saves it.

(Perhaps the converse order can also be problematic, where `onNotify` can overwrite any data saved to the order by Drupal Commerce behind the scenes (if any) during the `onReturn`-request)

	  
Is there a good way to handle this? (I.e. work around the race-condition to be able to save order-data in `onNotify`)

How would you do it?

---

(I have thought about Drupal's locking mechanism (would have worked, if it was possible to lock in `onReturn` all the way from before Drupal Commerce loads the order until after it has saved it - is that somehow possible? 
Perhaps it's somehow possible to reload the order in `onReturn` (and wait for `onNotify` to have completed)? Or create a wrapper (custom Controller) around `onReturn`, which calls `onReturns`, but locks first?). Perhaps there are other ways of `->setData` on the order which would survive, like "UPDATE commerce_order SET transaction_id = x WHERE y" instead of an object? Etc etc.)
	
I'm using Drupal 8.6, btw.