1313 */
1414class 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