13
13
14
14
use Symfony \Component \Process \Exception \InvalidArgumentException ;
15
15
use Symfony \Component \Process \Exception \LogicException ;
16
+ use Symfony \Component \Process \Exception \ProcessTimedOutException ;
16
17
use Symfony \Component \Process \Exception \RuntimeException ;
17
18
18
19
/**
@@ -44,7 +45,9 @@ class Process
44
45
private $ env ;
45
46
private $ stdin ;
46
47
private $ starttime ;
48
+ private $ lastOutputTime ;
47
49
private $ timeout ;
50
+ private $ idleTimeout ;
48
51
private $ options ;
49
52
private $ exitcode ;
50
53
private $ fallbackExitcode ;
@@ -231,7 +234,7 @@ public function start($callback = null)
231
234
throw new RuntimeException ('Process is already running ' );
232
235
}
233
236
234
- $ this ->starttime = microtime (true );
237
+ $ this ->starttime = $ this -> lastOutputTime = microtime (true );
235
238
$ this ->stdout = '' ;
236
239
$ this ->stderr = '' ;
237
240
$ this ->incrementalOutputOffset = 0 ;
@@ -795,6 +798,7 @@ public function stop($timeout = 10, $signal = null)
795
798
*/
796
799
public function addOutput ($ line )
797
800
{
801
+ $ this ->lastOutputTime = microtime (true );
798
802
$ this ->stdout .= $ line ;
799
803
}
800
804
@@ -805,6 +809,7 @@ public function addOutput($line)
805
809
*/
806
810
public function addErrorOutput ($ line )
807
811
{
812
+ $ this ->lastOutputTime = microtime (true );
808
813
$ this ->stderr .= $ line ;
809
814
}
810
815
@@ -835,39 +840,53 @@ public function setCommandLine($commandline)
835
840
/**
836
841
* Gets the process timeout.
837
842
*
838
- * @return integer |null The timeout in seconds or null if it's disabled
843
+ * @return float |null The timeout in seconds or null if it's disabled
839
844
*/
840
845
public function getTimeout ()
841
846
{
842
847
return $ this ->timeout ;
843
848
}
844
849
850
+ /**
851
+ * Gets the process idle timeout.
852
+ *
853
+ * @return float|null
854
+ */
855
+ public function getIdleTimeout ()
856
+ {
857
+ return $ this ->idleTimeout ;
858
+ }
859
+
845
860
/**
846
861
* Sets the process timeout.
847
862
*
848
863
* To disable the timeout, set this value to null.
849
864
*
850
- * @param float|null $timeout The timeout in seconds
865
+ * @param integer| float|null $timeout The timeout in seconds
851
866
*
852
867
* @return self The current Process instance
853
868
*
854
869
* @throws InvalidArgumentException if the timeout is negative
855
870
*/
856
871
public function setTimeout ($ timeout )
857
872
{
858
- if (null === $ timeout ) {
859
- $ this ->timeout = null ;
860
-
861
- return $ this ;
862
- }
863
-
864
- $ timeout = (float ) $ timeout ;
873
+ $ this ->timeout = $ this ->validateTimeout ($ timeout );
865
874
866
- if ($ timeout < 0 ) {
867
- throw new InvalidArgumentException ('The timeout value must be a valid positive integer or float number. ' );
868
- }
875
+ return $ this ;
876
+ }
869
877
870
- $ this ->timeout = $ timeout ;
878
+ /**
879
+ * Sets the process idle timeout.
880
+ *
881
+ * @param integer|float|null $timeout
882
+ *
883
+ * @return self The current Process instance.
884
+ *
885
+ * @throws InvalidArgumentException if the timeout is negative
886
+ */
887
+ public function setIdleTimeout ($ timeout )
888
+ {
889
+ $ this ->idleTimeout = $ this ->validateTimeout ($ timeout );
871
890
872
891
return $ this ;
873
892
}
@@ -1078,7 +1097,13 @@ public function checkTimeout()
1078
1097
if (0 < $ this ->timeout && $ this ->timeout < microtime (true ) - $ this ->starttime ) {
1079
1098
$ this ->stop (0 );
1080
1099
1081
- throw new RuntimeException ('The process timed-out. ' );
1100
+ throw new ProcessTimedOutException ($ this , ProcessTimedOutException::TYPE_GENERAL );
1101
+ }
1102
+
1103
+ if (0 < $ this ->idleTimeout && $ this ->idleTimeout < microtime (true ) - $ this ->lastOutputTime ) {
1104
+ $ this ->stop (0 );
1105
+
1106
+ throw new ProcessTimedOutException ($ this , ProcessTimedOutException::TYPE_IDLE );
1082
1107
}
1083
1108
}
1084
1109
@@ -1253,4 +1278,26 @@ private function hasSystemCallBeenInterrupted()
1253
1278
// stream_select returns false when the `select` system call is interrupted by an incoming signal
1254
1279
return isset ($ lastError ['message ' ]) && false !== stripos ($ lastError ['message ' ], 'interrupted system call ' );
1255
1280
}
1281
+
1282
+ /**
1283
+ * Validates and returns the filtered timeout.
1284
+ *
1285
+ * @param integer|float|null $timeout
1286
+ *
1287
+ * @return float|null
1288
+ */
1289
+ private function validateTimeout ($ timeout )
1290
+ {
1291
+ if (null === $ timeout ) {
1292
+ return null ;
1293
+ }
1294
+
1295
+ $ timeout = (float ) $ timeout ;
1296
+
1297
+ if ($ timeout < 0 ) {
1298
+ throw new InvalidArgumentException ('The timeout value must be a valid positive integer or float number. ' );
1299
+ }
1300
+
1301
+ return $ timeout ;
1302
+ }
1256
1303
}
0 commit comments