Skip to content

Commit bbe19e3

Browse files
committed
Handle MacOS gtimeout vs timeout
1 parent c622362 commit bbe19e3

File tree

1 file changed

+38
-1
lines changed

1 file changed

+38
-1
lines changed

src/AsyncTask.php

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Laravel\SerializableClosure\SerializableClosure;
99
use LogicException;
1010
use loophp\phposinfo\OsInfo;
11+
use RuntimeException;
1112

1213
/**
1314
* The common handler of an AsyncTask; this can be a closure (will be wrapped inside AsyncTask) or an interface instance.
@@ -32,6 +33,24 @@ class AsyncTask
3233
*/
3334
private int|null $timeLimit = 30;
3435

36+
/**
37+
* Indicates whether GNU coreutils is found in the system; in particular, we are looking for the timeout command inside coreutils.
38+
*
39+
* If null, indicates we haven't checked this yet.
40+
*
41+
* Always null in Windows since Windows-side does not require GNU coreutils.
42+
* @var bool|null
43+
*/
44+
private static bool|null $hasGnuCoreUtils = null;
45+
46+
/**
47+
* The name of the found timeout command inside GNU coreutils.
48+
*
49+
* It is known that older MacOS environments might have "gtimeout" instead of "timeout".
50+
* @var bool|null
51+
*/
52+
private static bool|null $timeoutCmdName = false;
53+
3554
/**
3655
* Creates an AsyncTask instance.
3756
* @param Closure|AsyncTaskInterface $theTask The task to be executed in the background.
@@ -97,7 +116,25 @@ public function start(): void
97116
// check time limit settings
98117
$timeoutClause = "";
99118
if ($this->timeLimit > 0) {
100-
$timeoutClause = "timeout {$this->timeLimit}";
119+
// do we really have timeout here?
120+
if (static::$hasGnuCoreUtils === null) {
121+
// haven't checked before; check
122+
$tmpOut = [];
123+
if (!exec("command -v timeout || command -v gtimeout", $tmpOut)) {
124+
// can't even check this
125+
throw new RuntimeException("AsyncTask failed to check whether GNU coreutils is installed");
126+
}
127+
// extract details
128+
$cmdName = $tmpOut[0] ?? null;
129+
static::$hasGnuCoreUtils = $cmdName ? true : false;
130+
static::$timeoutCmdName = $cmdName;
131+
unset($cmdName);
132+
}
133+
if (static::$hasGnuCoreUtils === false) {
134+
// can't do anything without GNU coreutils!
135+
throw new RuntimeException("AsyncTask time limit requires GNU coreutils, but GNU coreutils was not installed");
136+
}
137+
$timeoutClause = static::$timeoutCmdName . " {$this->timeLimit}";
101138
}
102139
$this->runnerProcess = Process::quietly()->start("nohup $timeoutClause $baseCommand");
103140
}

0 commit comments

Comments
 (0)