Skip to content

Commit 56a91c2

Browse files
committed
Limit max. sleep duration per loop iteration
1 parent 9abe6ed commit 56a91c2

File tree

1 file changed

+20
-19
lines changed

1 file changed

+20
-19
lines changed

src/Util/Loop.php

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,6 @@
1111
*/
1212
class Loop
1313
{
14-
/** Minimum time to wait between lock checks. In micro seconds. */
15-
private const MINIMUM_WAIT_US = 10_000;
16-
17-
/** Maximum time to wait between lock checks. In micro seconds. */
18-
private const MAXIMUM_WAIT_US = 500_000;
19-
2014
/** True while code execution is repeating */
2115
private bool $looping = false;
2216

@@ -63,34 +57,41 @@ public function execute(callable $code, float $timeout)
6357
// At this time, the lock will timeout.
6458
$deadlineTs = microtime(true) + $timeout;
6559

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

72-
return $result;
69+
break;
7370
}
7471

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

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

89-
$usecToSleep = min($usecRemaining, random_int((int) $min, (int) $max));
88+
usleep($sleepMicros);
89+
}
9090

91-
usleep($usecToSleep);
91+
if (microtime(true) >= $deadlineTs) {
92+
throw LockAcquireTimeoutException::create($timeout);
9293
}
9394

94-
throw LockAcquireTimeoutException::create($timeout);
95+
return $result;
9596
}
9697
}

0 commit comments

Comments
 (0)