@@ -57,15 +57,6 @@ class AsyncTask
5757 */
5858 private const LARAVEL_START = "LARAVEL_START " ;
5959
60- /**
61- * The epsilon time (in seconds) that will be added to the microtime to check for task timeouts.
62- *
63- * For some unknown reason, theoretical solutions that rely on (supposed) Unix behavior does not pass the tests,
64- * so we are implementing this as a temporary workaround.
65- * @var float
66- */
67- private const TIME_EPSILON = 0.1 ;
68-
6960 /**
7061 * The bitmask that can filter for fatal runtime errors.
7162 *
@@ -125,9 +116,13 @@ public function run(): void
125116 set_time_limit ($ this ->timeLimit );
126117 } else {
127118 // assume anything not Windows to be Unix
128- // we already set it to kill this task after the timeout, so we just need to install a listener
119+ // we already set it to kill this task after the timeout, so we just need to install a listener to catch the signal and exit gracefully
129120 pcntl_async_signals (true );
130- pcntl_signal (SIGTERM , [$ this , 'pcntlGracefulExit ' ]);
121+ pcntl_signal (SIGTERM , function () {
122+ // just exit is ok
123+ // exit asap so that our error checking inside shutdown functions can take place outside of the usual max_execution_time limit
124+ exit ();
125+ });
131126
132127 // and we also need to see the command name of our parent, to correctly track time
133128 $ this ->timerProcID = getmypid ();
@@ -191,8 +186,7 @@ public function start(): void
191186 }
192187 $ timeoutClause = static ::$ timeoutCmdName . " {$ this ->timeLimit }" ;
193188 }
194- // $this->runnerProcess = Process::quietly()->start("nohup $timeoutClause $baseCommand >/dev/null 2>&1");
195- $ this ->runnerProcess = Process::quietly ()->start ("nohup $ timeoutClause $ baseCommand " );
189+ $ this ->runnerProcess = Process::quietly ()->start ("nohup $ timeoutClause $ baseCommand >/dev/null 2>&1 " );
196190 }
197191
198192 /**
@@ -277,19 +271,6 @@ public function withoutTimeLimit(): static
277271 return $ this ;
278272 }
279273
280- /**
281- * On Unix only. Signal handler for SIGTERM to catch it and exit() instead.
282- *
283- * NOT FOR EXTERNAL USE!
284- * @return never
285- */
286- public function pcntlGracefulExit (): never
287- {
288- // just exit is ok
289- // exit asap so that our error checking inside shutdown functions can take place outside of the usual max_execution_time limit
290- exit ();
291- }
292-
293274 /**
294275 * A shutdown function.
295276 *
@@ -323,7 +304,6 @@ private function hasTimedOut(): bool
323304 $ lastError = error_get_last ();
324305 if ($ lastError !== null && ($ lastError ['type ' ] & self ::FATAL_ERROR_BITMASK )) {
325306 // has fatal error; is it our timeout error?
326- fwrite (STDERR , "error_get_last " . json_encode ($ lastError ) . PHP_EOL );
327307 return str_contains ($ lastError ['message ' ], "Maximum execution time " );
328308 }
329309 unset($ lastError );
@@ -338,8 +318,6 @@ private function hasTimedOut(): bool
338318
339319 // check LARAVEL_START with microtime
340320 $ timeElapsed = microtime (true ) - $ this ->laravelStartVal ;
341- // temp let runner print me the stats
342- fwrite (STDERR , "microtime elapsed $ timeElapsed " . PHP_EOL );
343321 if ($ timeElapsed >= $ this ->timeLimit ) {
344322 // yes
345323 return true ;
@@ -354,12 +332,10 @@ private function hasTimedOut(): bool
354332 $ tempOut = exec ("ps -p {$ this ->timerProcID } -o etimes= " );
355333 // this must exist (we are still running!), otherwise it indicates the kernel is broken and we can go grab a chicken dinner instead
356334 $ timeElapsed = (int ) $ tempOut ;
357- fwrite (STDERR , "proc-stat elapsed $ timeElapsed " . PHP_EOL );
358335 unset($ tempOut );
359- // we believe there is a seemingly unexplainable behavior that results in the etimes to be off-by-1 when it would be terminated by `timeout`
360- // e.g., when killed by `timeout` with time limit = 7, the etime might actually be 6.999999... and it gets displayed as 6, thus failing the check
361- // so, just to be sure, we will make it timeout when killed at the last second to the time limit
362- return $ timeElapsed >= $ this ->timeLimit ;
336+ // it seems like etimes can get random off-by-1 inaccuracies (e.g. timeout supposed to be 7, but etimes sees 6.99999... and prints "6")
337+ // so, we will still trigger the timeout handler if the runner is killed in its last second of execution; we trust the timeout command for this
338+ return $ timeElapsed + 1 >= $ this ->timeLimit ;
363339 }
364340 }
365341
0 commit comments