Skip to content

Commit 7e66688

Browse files
committed
Limit max. sleep duration per loop iteration
1 parent 4fe9681 commit 7e66688

File tree

1 file changed

+20
-19
lines changed

1 file changed

+20
-19
lines changed

src/Util/Loop.php

+20-19
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,6 @@
1313
*/
1414
class Loop
1515
{
16-
/** Minimum time to wait between lock checks. In micro seconds. */
17-
private const MINIMUM_WAIT_US = 10_000;
18-
19-
/** Maximum time to wait between lock checks. In micro seconds. */
20-
private const MAXIMUM_WAIT_US = 500_000;
21-
2216
/** True while code execution is repeating */
2317
private bool $looping = false;
2418

@@ -65,34 +59,41 @@ public function execute(callable $code, float $timeout)
6559
// At this time, the lock will timeout.
6660
$deadlineTs = microtime(true) + $timeout;
6761

62+
$minWaitSecs = 0.1e-3; // 0.1 ms
63+
$maxWaitSecs = max(0.05, min(25, $timeout / 120)); // 50 ms to 25 s, based on timeout
64+
6865
$result = null;
69-
for ($i = 0; $this->looping && microtime(true) < $deadlineTs; ++$i) { // @phpstan-ignore booleanAnd.leftAlwaysTrue
66+
for ($i = 0;; ++$i) {
7067
$result = $code();
7168
if (!$this->looping) { // @phpstan-ignore booleanNot.alwaysFalse
7269
// The $code callback has called $this->end() and the lock has been acquired.
7370

74-
return $result;
71+
break;
7572
}
7673

7774
// Calculate max time remaining, don't sleep any longer than that.
78-
$usecRemaining = LockUtil::getInstance()->castFloatToInt(($deadlineTs - microtime(true)) * 1e6);
79-
80-
// We've ran out of time.
81-
if ($usecRemaining <= 0) {
75+
$remainingSecs = $deadlineTs - microtime(true);
76+
if ($remainingSecs <= 0) {
8277
break;
8378
}
8479

85-
$min = min(
86-
self::MINIMUM_WAIT_US * 1.25 ** $i,
87-
self::MAXIMUM_WAIT_US
80+
$minSecs = min(
81+
$minWaitSecs * 1.5 ** $i,
82+
max($minWaitSecs, $maxWaitSecs / 2)
83+
);
84+
$maxSecs = min($minSecs * 2, $maxWaitSecs);
85+
$sleepMicros = min(
86+
max(10, LockUtil::getInstance()->castFloatToInt($remainingSecs * 1e6)),
87+
random_int(LockUtil::getInstance()->castFloatToInt($minSecs * 1e6), LockUtil::getInstance()->castFloatToInt($maxSecs * 1e6))
8888
);
89-
$max = min($min * 2, self::MAXIMUM_WAIT_US);
9089

91-
$usecToSleep = min($usecRemaining, random_int((int) $min, (int) $max));
90+
usleep($sleepMicros);
91+
}
9292

93-
usleep($usecToSleep);
93+
if (microtime(true) >= $deadlineTs) {
94+
throw LockAcquireTimeoutException::create($timeout);
9495
}
9596

96-
throw LockAcquireTimeoutException::create($timeout);
97+
return $result;
9798
}
9899
}

0 commit comments

Comments
 (0)