You are here

Locking mechanisms in Drupal 9

Same name and namespace in other branches
  1. 8 core/lib/Drupal/Core/Lock/LockBackendInterface.php \Drupal\Core\Lock\lock
  2. 10 core/lib/Drupal/Core/Lock/LockBackendInterface.php \Drupal\Core\Lock\lock

Functions to coordinate long operations across requests.

In most environments, multiple Drupal page requests (a.k.a. threads or processes) will execute in parallel. This leads to potential conflicts or race conditions when two requests execute the same code at the same time. For instance, some implementations of hook_cron() implicitly assume they are running only once, rather than having multiple calls in parallel. To prevent problems with such code, the cron system uses a locking process to ensure that cron is not started again if it is already running.

To avoid these types of conflicts, Drupal has a cooperative, advisory lock system. Any long-running operation that could potentially be attempted in parallel by multiple requests should try to acquire a lock before proceeding. By obtaining a lock, one request notifies any other requests that a specific operation is in progress which must not be executed in parallel.

To use this API, pick a unique name for the lock. A sensible choice is the name of the function performing the operation. Here is a simple example:

function mymodule_long_operation() {
  $lock = \Drupal::lock();
  if ($lock
    ->acquire('mymodule_long_operation')) {

    // Do the long operation here.
    // ...
    $lock
      ->release('mymodule_long_operation');
  }
}

If a function acquires a lock it should always release it when the operation is complete by calling $lock->release(), as in the example.

A function that has acquired a lock may attempt to renew a lock (extend the duration of the lock) by calling $lock->acquire() again during the operation. Failure to renew a lock is indicative that another request has acquired the lock, and that the current operation may need to be aborted.

If a function fails to acquire a lock it may either immediately return, or it may call $lock->wait() if the rest of the current page request requires that the operation in question be complete. After $lock->wait() returns, the function may again attempt to acquire the lock, or may simply allow the page request to proceed on the assumption that a parallel request completed the operation.

$lock->acquire() and $lock->wait() will automatically break (delete) a lock whose duration has exceeded the timeout specified when it was acquired.

The following limitations in this implementation should be carefully noted:

  • Time: Timestamps are derived from the local system clock of the environment the code is executing in. The orderly progression of time from this viewpoint can be disrupted by external events such as NTP synchronization and operator intervention. Where multiple web servers are involved in serving the site, they will have their own independent clocks, introducing another source of error in the time keeping process. Timeout values applied to locks must therefore be considered approximate, and should not be relied upon.
  • Uniqueness: Uniqueness of lock names is not enforced. The impact of the use of a common lock name will depend on what processes and resources the lock is being used to manage.
  • Sharing: There is limited support for resources shared across sites. The locks are stored as rows in the semaphore table and, as such, they have the same visibility as the table. If resources managed by a lock are shared across sites then the semaphore table must be shared across sites as well. This is a binary situation: either all resources are shared and the semaphore table is shared or no resources are shared and the semaphore table is not shared. Mixed mode operation is not supported.

End of "defgroup lock".

File

core/lib/Drupal/Core/Lock/LockBackendInterface.php, line 5

Functions

Namesort descending Location Description
Drupal::lock core/lib/Drupal.php Returns the locking layer instance.

Classes

Namesort descending Location Description
DatabaseLockBackend core/lib/Drupal/Core/Lock/DatabaseLockBackend.php Defines the database lock backend. This is the default backend in Drupal.
LockBackendAbstract core/lib/Drupal/Core/Lock/LockBackendAbstract.php Non backend related common methods implementation for lock backends.
NullLockBackend core/lib/Drupal/Core/Lock/NullLockBackend.php Defines a Null lock backend.
PersistentDatabaseLockBackend core/lib/Drupal/Core/Lock/PersistentDatabaseLockBackend.php Defines the persistent database lock backend. This backend is global for this Drupal installation.

Interfaces

Namesort descending Location Description
LockBackendInterface core/lib/Drupal/Core/Lock/LockBackendInterface.php Lock backend interface.