Skip to content

Commit 02d1ba7

Browse files
committed
Limit max. sleep duration per loop iteration
1 parent 7cb08aa commit 02d1ba7

File tree

1 file changed

+21
-24
lines changed

1 file changed

+21
-24
lines changed

src/util/Loop.php

+21-24
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,6 @@
1313
*/
1414
class Loop
1515
{
16-
/**
17-
* Minimum time that we want to wait, between lock checks. In micro seconds.
18-
*/
19-
private const MINIMUM_WAIT_US = 1e4; // 0.01 seconds
20-
21-
/**
22-
* Maximum time that we want to wait, between lock checks. In micro seconds.
23-
*/
24-
private const MAXIMUM_WAIT_US = 5e5; // 0.50 seconds
25-
2616
/** @var float The timeout in seconds */
2717
private $timeout;
2818

@@ -80,10 +70,13 @@ public function execute(callable $code)
8070
$this->looping = true;
8171

8272
// At this time, the lock will time out.
83-
$deadline = microtime(true) + $this->timeout;
73+
$deadlineTs = microtime(true) + $this->timeout;
74+
75+
$minWaitSecs = 0.1e-3; // 0.1 ms
76+
$maxWaitSecs = max(0.05, min(25, $this->timeout / 120)); // 50 ms to 25 s, based on timeout
8477

8578
$result = null;
86-
for ($i = 0; $this->looping && microtime(true) < $deadline; ++$i) { // @phpstan-ignore booleanAnd.leftAlwaysTrue
79+
for ($i = 0;; ++$i) {
8780
$result = $code();
8881
if (!$this->looping) { // @phpstan-ignore booleanNot.alwaysFalse
8982
// The $code callback has called $this->end() and the lock has been acquired.
@@ -92,24 +85,28 @@ public function execute(callable $code)
9285
}
9386

9487
// Calculate max time remaining, don't sleep any longer than that.
95-
$usecRemaining = (int) (($deadline - microtime(true)) * 1e6);
96-
97-
// We've ran out of time.
98-
if ($usecRemaining <= 0) {
99-
throw TimeoutException::create($this->timeout);
88+
$remainingSecs = $deadlineTs - microtime(true);
89+
if ($remainingSecs <= 0) {
90+
break;
10091
}
10192

102-
$min = min(
103-
(int) self::MINIMUM_WAIT_US * 1.25 ** $i,
104-
self::MAXIMUM_WAIT_US
93+
$minSecs = min(
94+
$minWaitSecs * 1.5 ** $i,
95+
max($minWaitSecs, $maxWaitSecs / 2)
96+
);
97+
$maxSecs = min($minSecs * 2, $maxWaitSecs);
98+
$sleepMicros = min(
99+
max(10, (int) ($remainingSecs * 1e6)),
100+
random_int((int) ($minSecs * 1e6), (int) ($maxSecs * 1e6))
105101
);
106-
$max = min($min * 2, self::MAXIMUM_WAIT_US);
107102

108-
$usecToSleep = min($usecRemaining, random_int((int) $min, (int) $max));
103+
usleep($sleepMicros);
104+
}
109105

110-
usleep($usecToSleep);
106+
if (microtime(true) >= $deadlineTs) {
107+
throw TimeoutException::create($this->timeout);
111108
}
112109

113-
throw TimeoutException::create($this->timeout);
110+
return $result;
114111
}
115112
}

0 commit comments

Comments
 (0)