Improve commerce entities locking

Created on 14 April 2014, over 10 years ago
Updated 8 October 2023, about 1 year ago

Order locking is a hard subject, and history has shown that the implementation we have in Drupal Commerce is severely lacking.

Background

Commerce by default locks the order every time, because it cannot know what the order will be used for, and whether it will be saved.
However, a vast number of order loads is for reading purposes only, and never results in a save.
This includes all views, access checking, link outputting, token generation, etc.
For example, our code ensures that an admin viewing the order view makes the order unavailable for the customer to view, and vice versa.
All this results in a number of deadlocks, and people having to disable locking in production (two examples I know are RoyalMail and since today, CommerceGuys Marketplace). Of course, locking is there for a reason, so disabling it opens you to subtle errors and can increase problems.

Related issues:
#1514618: Developer documentation: Loading order entities without considering locking can cause problems β†’
#1320062: SQLSTATE[HY000]: General error: 1205 Lock wait timeout exceeded β†’
#1608294: Provide a way to load an order without locking β†’

Proposed solution

1) Allow orders to be loaded read-only.
2) Don't allow unlocked orders to be saved or deleted, throw an exception in that case.
3) Convert the admin/user order view pages to load the orders read-only
4) Disable locking for safe order views (any other than the cart one, basically).

πŸ“Œ Task
Status

Needs review

Version

1.0

Component

Order

Created by

πŸ‡·πŸ‡ΈSerbia bojanz

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • πŸ‡ΊπŸ‡ΈUnited States kjl

    If you want to test changing the commerce_order_load() Locking Mode in D7 without hacking core, you can do something like the following:

    class ExampleExtender extends SelectQueryExtender {
      public function __toString() {
      $query = parent::__toString();
      $query .= ' ' LOCK IN SHARE MODE';
      return $query;
      }
    }
    
    function my_module_query_alter(QueryAlterableInterface &$query) {
      $tags = array_flip(array_keys($query->alterTags));
      if (isset($tags['commerce_order_load_multiple'])) { 
        $query->forUpdate(FALSE);
        $query = $query->extend('ExampleExtender');
      }
    }
    

    Note that assigning the extender result back to $query is required, as a new object is returned from extend().

Production build 0.71.5 2024