Allow subsecond delays for lock_wait

Created on 23 September 2013, about 11 years ago
Updated 11 July 2024, 3 months ago

lock_acquire() allows float timeouts but due to an order of operations issue in lock_wait only integers can be used for the delay. Therefore the delay can be at least one second. For subsecond locks, i.e. for a simple throttle method for requests being sent to a third party API, this isn't ideal so wrapping the point conversion before typecasting would be preferable.

Patch to follow.

πŸ“Œ Task
Status

Active

Version

11.0 πŸ”₯

Component
LockΒ  β†’

Last updated 3 months ago

No maintainer
Created by

πŸ‡ΊπŸ‡ΈUnited States elliotttf

Live updates comments and jobs are added and updated live.
  • Needs backport to D7

    After being applied to the 8.x branch, it should be considered for backport to the 7.x branch. Note: This tag should generally remain even after the backport has been written, approved, and committed.

  • Needs issue summary update

    Issue summaries save everyone time if they are kept up-to-date. See Update issue summary task instructions.

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 Kingdom catch

    I don't think the issue summary is correct.

    :wait() accepts a minimum value of a second. However, the minimum wait time isn't one second, it's 25 milliseconds.

     // Pause the process for short periods between calling
        // lock_may_be_available(). This prevents hitting the database with constant
        // database queries while waiting, which could lead to performance issues.
        // However, if the wait period is too long, there is the potential for a
        // large number of processes to be blocked waiting for a lock, especially
        // if the item being rebuilt is commonly requested. To address both of these
        // concerns, begin waiting for 25ms, then add 25ms to the wait period each
        // time until it reaches 500ms. After this point polling will continue every
        // 500ms until $delay is reached.
    
        // $delay is passed in seconds, but we will be using usleep(), which takes
        // microseconds as a parameter. Multiply it by 1 million so that all
        // further numbers are equivalent.
        $delay = (int) $delay * 1000000;
    
        // Begin sleeping at 25ms.
        $sleep = 25000;
    

    The only way it would reach 1 second is if the lock really is held for 1 second, but that seems fine?

    Moving to a feature request and marking needs more info - would like the issue summary to spell out why the existing polling logic doesn't cover this.

  • πŸ‡³πŸ‡ΏNew Zealand quietone

    This was a bugsmash daily target yesterday, adding tag.

  • Status changed to Active 3 months ago
  • πŸ‡·πŸ‡ΊRussia Chi

    The code below will go to infinity loop.

    $lock = \Drupal::lock();
    
    $result = $lock->acquire('example', 5);
    while ($lock->wait('example', 0.5)) {
      echo '.';
    }
    
    echo 'Done!', \PHP_EOL;
    

    I know, that per \Drupal\Core\Lock\LockBackendInterface::wait() the $delay parameter must be an integer but it doesn't have native typehint so no one stops your from passing floats. Note that timeout parameter in \Drupal\Core\Lock\LockBackendInterface::acquire() is a float, even though it has same default value. That's confusing.

    I think this is neither a bug nor a feature. It's a task to improve DX of this service.

Production build 0.71.5 2024