diff --git a/src/ProcessPool.php b/src/ProcessPool.php index 892b48e..81f789c 100644 --- a/src/ProcessPool.php +++ b/src/ProcessPool.php @@ -173,6 +173,20 @@ public function startProcess(): ProcessPoolRequest $proc = array_pop($this->unassignedProcs); $this->runningProcs[] = $proc; + // Make sure output is cleared + if ($proc->hasStderrData() || $proc->hasStdoutData()) + { + $stderrLines = []; + $stdoutLines = []; + while ($proc->hasStderrData()) + $stderrLines[] = $proc->getStderrResponse(); + while ($proc->hasStdoutData()) + $stdoutLines[] = $proc->getStdoutResponse(); + $proc->markAsFailed(); + $this->releaseProcess($proc); + throw new ProcessPoolProcessOutputBeforeStartingException($stderrLines, $stdoutLines); + } + return $proc; } diff --git a/src/ProcessPoolProcessOutputBeforeStartingException.php b/src/ProcessPoolProcessOutputBeforeStartingException.php new file mode 100644 index 0000000..eb4ae9b --- /dev/null +++ b/src/ProcessPoolProcessOutputBeforeStartingException.php @@ -0,0 +1,45 @@ +stderrLines = $stderrLines; + $this->stdoutLines = $stdoutLines; + } + + /** + * Get STDERR lines + * + * @return string[] STDERR lines + */ + public function getStderrLines(): array + { + return $this->stderrLines; + } + + /** + * Get STDOUT lines + * + * @return string[] STDOUT lines + */ + public function getStdoutLines(): array + { + return $this->stdoutLines; + } +} diff --git a/tests/.phpunit.result.cache b/tests/.phpunit.result.cache index a4ecdc5..584540e 100644 --- a/tests/.phpunit.result.cache +++ b/tests/.phpunit.result.cache @@ -1 +1 @@ -{"version":1,"defects":{"ProcessPoolTest::testProcessPool":3,"ProcessPoolTest::testProcessPoolErrors":3,"ProcessPoolTest::testProcessPoolWithLongMessage":4,"ProcessPoolTest::testInvalidResponse":3,"ProcessPoolTest::testProcessPoolNoRelease":3,"ProcessPoolTest::testProcessPoolWithLongResponse":4,"ProcessPoolTest::testProcessPoolEndOfFile":4,"ProcessPoolRequestTest::testProcessPoolEndOfFile":3,"ProcessPoolRequestTest::testProcessPoolInvalidMessage":3,"ProcessPoolTest::testProcessPoolWithLongStderrResponse":3,"ProcessPoolRequestTest::testProcessPoolParentClosedInput":3,"ProcessPoolRequestTest::testProcessPoolHangOnExit":4,"ProcessPoolTest::testProcessPoolExit":3,"ProcessPoolTest::testProcessPoolSlientExit":4,"ProcessPoolTest::testProcessPoolSilentExit":3,"ProcessPoolTest::testProcessPoolExitHang":3,"ProcessPoolRequestTest::testPeek":3,"ProcessPoolRequestTest::testWaitForStdoutOrStderr":4,"ProcessPoolRequestTest::testWaitForStderr":3,"ProcessPoolRequestTest::testWaitForStdout":3,"ProcessPoolTest::testProcessPoolShutDown":3,"ProcessPoolTest::testProcessPoolNoReadBeforeRelease":3,"ProcessPoolTest::testProcessPoolMarkedAsFailed":3},"times":{"ProcessPoolTest::testInvalidResponse":0.007,"ProcessPoolTest::testInvalidMaxSpares":0.003,"ProcessPoolTest::testProcessPool":0.444,"ProcessPoolTest::testProcessPoolErrors":0.107,"ProcessPoolTest::testProcessPoolNoRelease":0.098,"ProcessPoolTest::testProcessPoolWithLongMessage":0.096,"ProcessPoolTest::testProcessPoolWithLongWriteMessage":0.122,"ProcessPoolTest::testProcessPoolWithLongResponse":0.097,"ProcessPoolTest::testProcessPoolWithLongStderrResponse":0.15,"ProcessPoolTest::testProcessPoolEndOfFile":0.099,"ProcessPoolRequestTest::testProcessPoolEndOfFile":0.092,"ProcessPoolRequestTest::testProcessPoolInvalidMessage":0.209,"ProcessPoolRequestTest::testProcessPoolParentClosedInput":0.126,"ProcessPoolRequestTest::testProcessPoolHangOnExit":0.251,"ProcessPoolTest::testProcessPoolExit":0.097,"ProcessPoolTest::testProcessPoolSlientExit":0.101,"ProcessPoolTest::testProcessPoolSilentExit":0.099,"ProcessPoolTest::testProcessPoolExitHang":0.108,"ProcessPoolRequestTest::testPeek":0.113,"ProcessPoolRequestTest::testWaitForStdoutOrStderr":0.1,"ProcessPoolRequestTest::testWaitForStdout":0.113,"ProcessPoolRequestTest::testWaitForStderr":0.124,"ProcessPoolTest::testProcessPoolShutDown":0.131,"ProcessPoolTest::testProcessPoolNoReadBeforeRelease":0.101,"ProcessPoolTest::testProcessPoolNoReadBeforeRead":0.103,"ProcessPoolTest::testProcessPoolMarkedAsFailed":0.19}} \ No newline at end of file +{"version":1,"defects":{"ProcessPoolRequestTest::testWaitForStdout":3,"ProcessPoolRequestTest::testWaitForStderr":3,"ProcessPoolRequestTest::testProcessPoolInvalidMessage":3,"ProcessPoolRequestTest::testProcessPoolParentClosedInput":3,"ProcessPoolTest::testProcessPool":3,"ProcessPoolTest::testProcessPoolErrors":3,"ProcessPoolTest::testProcessPoolMarkedAsFailed":3,"ProcessPoolTest::testProcessPoolErrorBeforeResponse":3,"ProcessPoolTest::testProcessPoolNoReadBeforeRead":3,"ProcessPoolTest::testProcessPoolWithLongMessage":3,"ProcessPoolTest::testProcessPoolWithLongResponse":3,"ProcessPoolTest::testProcessPoolWithLongStderrResponse":3,"ProcessPoolTest::testProcessPoolExit":3,"ProcessPoolTest::testProcessPoolExitHang":3,"ProcessPoolTest::testProcessPoolShutDown":3},"times":{"ProcessPoolRequestTest::testWaitForStdout":0.109,"ProcessPoolRequestTest::testWaitForStderr":0.117,"ProcessPoolRequestTest::testProcessPoolInvalidMessage":0.211,"ProcessPoolRequestTest::testProcessPoolParentClosedInput":0.115,"ProcessPoolTest::testInvalidMaxSpares":0.002,"ProcessPoolTest::testProcessPool":0.454,"ProcessPoolTest::testProcessPoolErrors":0.111,"ProcessPoolTest::testProcessPoolMarkedAsFailed":0.197,"ProcessPoolTest::testProcessPoolErrorBeforeResponse":0.473,"ProcessPoolTest::testProcessPoolNoReadBeforeRead":0.101,"ProcessPoolTest::testProcessPoolWithLongMessage":0.093,"ProcessPoolTest::testProcessPoolWithLongResponse":0.092,"ProcessPoolTest::testProcessPoolWithLongStderrResponse":0.092,"ProcessPoolTest::testProcessPoolExit":0.092,"ProcessPoolTest::testProcessPoolSilentExit":0.097,"ProcessPoolTest::testProcessPoolExitHang":0.094,"ProcessPoolTest::testProcessPoolShutDown":0.119}} \ No newline at end of file diff --git a/tests/TestAuxFiles/PhpUnitTestProcess.php b/tests/TestAuxFiles/PhpUnitTestProcess.php index 4ab372f..04d035d 100644 --- a/tests/TestAuxFiles/PhpUnitTestProcess.php +++ b/tests/TestAuxFiles/PhpUnitTestProcess.php @@ -63,6 +63,13 @@ public function handleRequest(string $data) // Check if we should output request count else if ($data === 'req-count') print $this->numRequests; + // Check if we should test error with late STDOUT + else if ($data === 'error-late-stdout') + { + fwrite(STDERR, 'Error, then sleep.'); + usleep(20000); + print 'Done sleep'; + } else { // Output MD5 of data diff --git a/tests/TestCases/ProcessPoolTest.php b/tests/TestCases/ProcessPoolTest.php index 133310b..37c0461 100644 --- a/tests/TestCases/ProcessPoolTest.php +++ b/tests/TestCases/ProcessPoolTest.php @@ -7,6 +7,7 @@ use ssigwart\ProcessPool\ProcessPool; use ssigwart\ProcessPool\ProcessPoolException; use ssigwart\ProcessPool\ProcessPoolPoolExhaustedException; +use ssigwart\ProcessPool\ProcessPoolProcessOutputBeforeStartingException; /** * Process pool test @@ -172,6 +173,50 @@ public function testProcessPoolMarkedAsFailed(): void $pool->releaseProcess($req); } + /** + * Test process pool error before response + */ + public function testProcessPoolErrorBeforeResponse(): void + { + $poolSize = 1; + $pool = new ProcessPool($poolSize, $poolSize, 'php processes/phpUnitProcesses.php', realpath(__DIR__ . DIRECTORY_SEPARATOR . '..')); + + $req = $pool->startProcess(); + $req->sendRequest('req-count'); + self::assertEquals('1', $req->getStdoutResponse(), 'MD5 incorrect.'); + $pool->releaseProcess($req); + + $req = $pool->startProcess(); + $req->sendRequest('req-count'); + self::assertEquals('2', $req->getStdoutResponse(), 'MD5 incorrect.'); + $pool->releaseProcess($req); + + $req = $pool->startProcess(); + $req->sendRequest('error-late-stdout'); + usleep(5000); + self::assertEquals('Error, then sleep.', $req->getStderrResponse(), 'MD5 incorrect.'); + self::assertEquals(false, $req->hasStdoutData(), 'No STDOUT expected.'); + $pool->releaseProcess($req); + usleep(250000); + + try { + $req = $pool->startProcess(); + self::fail('Expected ProcessPoolProcessOutputBeforeStartingException.'); + } catch (ProcessPoolProcessOutputBeforeStartingException $e) { + self::assertEquals([], $e->getStderrLines()); + self::assertEquals(['Done sleep'], $e->getStdoutLines()); + } + $req = $pool->startProcess(); + $req->sendRequest('req-count'); + self::assertEquals('1', $req->getStdoutResponse(), 'MD5 incorrect.'); + $pool->releaseProcess($req); + + $req = $pool->startProcess(); + $req->sendRequest('req-count'); + self::assertEquals('2', $req->getStdoutResponse(), 'MD5 incorrect.'); + $pool->releaseProcess($req); + } + /** * Test pool release before read */