From eb8be54c6a52a1e0371b846a308f9b0b2ccae0b9 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Tue, 30 Aug 2016 14:08:24 +0200 Subject: [PATCH 001/133] added WorkerCommandOutput interface and implementation for process stdin --- .../Command/ProcessStreamCommandOutput.php | 43 +++++++++++++++++++ .../Worker/Command/WorkerCommandOutput.php | 15 +++++++ 2 files changed, 58 insertions(+) create mode 100644 src/SAREhub/Component/Worker/Command/ProcessStreamCommandOutput.php create mode 100644 src/SAREhub/Component/Worker/Command/WorkerCommandOutput.php diff --git a/src/SAREhub/Component/Worker/Command/ProcessStreamCommandOutput.php b/src/SAREhub/Component/Worker/Command/ProcessStreamCommandOutput.php new file mode 100644 index 0000000..9a122bc --- /dev/null +++ b/src/SAREhub/Component/Worker/Command/ProcessStreamCommandOutput.php @@ -0,0 +1,43 @@ +processInputStream = $process->getInput(); + $this->process = $process; + $this->confirmationPattern = $confirmationPattern; + } + + public function sendCommand(WorkerCommand $command) { + fwrite($this->processInputStream, json_encode(($command))."\n"); + } + + public function getCommandConfirmation() { + $this->processOutput .= $this->process->getIncrementalOutput(); + if (!empty($this->processOutput)) { + $confirmationPos = strpos($this->processOutput, $this->confirmationPattern); + if ($confirmationPos !== false) { + $this->processOutput = substr($this->processOutput, $confirmationPos); + return true; + } + } + + return false; + } +} \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Command/WorkerCommandOutput.php b/src/SAREhub/Component/Worker/Command/WorkerCommandOutput.php new file mode 100644 index 0000000..a50f5bd --- /dev/null +++ b/src/SAREhub/Component/Worker/Command/WorkerCommandOutput.php @@ -0,0 +1,15 @@ + Date: Tue, 30 Aug 2016 14:09:27 +0200 Subject: [PATCH 002/133] added ProcessStreamWorkerCommandOutput tests --- .../ProcessStreamCommandOutputTest.php | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 tests/unit/SAREhub/Component/Worker/Command/ProcessStreamCommandOutputTest.php diff --git a/tests/unit/SAREhub/Component/Worker/Command/ProcessStreamCommandOutputTest.php b/tests/unit/SAREhub/Component/Worker/Command/ProcessStreamCommandOutputTest.php new file mode 100644 index 0000000..e2be7c2 --- /dev/null +++ b/tests/unit/SAREhub/Component/Worker/Command/ProcessStreamCommandOutputTest.php @@ -0,0 +1,53 @@ +processMock = $this->getMockBuilder(Process::class)->disableOriginalConstructor()->getMock(); + $this->processInputStream = fopen('php://memory', 'w+'); + $this->processMock->method('getInput')->willReturn($this->processInputStream); + $this->commandOutput = new ProcessStreamCommandOutput($this->processMock); + } + + + public function testSendCommand() { + $commandMock = $this->getMockBuilder(WorkerCommand::class)->disableOriginalConstructor()->getMock(); + $commandMock->expects($this->atLeast(2))->method('jsonSerialize')->willReturn([ + 'name' => 'test', + 'parameters' => [] + ]); + + $this->commandOutput->sendCommand($commandMock); + fseek($this->processInputStream, 0); + $this->assertEquals(json_encode($commandMock), trim(fgets($this->processInputStream))); + fclose($this->processInputStream); + } + + public function testGetCommandConfirmation() { + $this->processMock->method('getIncrementalOutput')->willReturn("1\ngfdgdf"); + $this->assertEquals('1', $this->commandOutput->getCommandConfirmation()); + fclose($this->processInputStream); + } + + public function testGetCommandConfirmationForPartialOutputFromProcess() { + $this->processMock->method('getIncrementalOutput')->willReturnOnConsecutiveCalls("test1", "\nafter", "after"); + $this->assertFalse($this->commandOutput->getCommandConfirmation()); + $this->assertTrue($this->commandOutput->getCommandConfirmation()); + fclose($this->processInputStream); + } + + +} From 7aa2e90ec6f2aeb06dff6fe85c3143c296401b05 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Tue, 30 Aug 2016 14:09:53 +0200 Subject: [PATCH 003/133] fixes --- composer.json | 8 +++++--- phpunit.xml | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index f1120fc..06e7535 100644 --- a/composer.json +++ b/composer.json @@ -9,13 +9,15 @@ } ], "require-dev": { - "phpunit/phpunit": "5.4.*", + "phpunit/phpunit": "5.*", "codeclimate/php-test-reporter": "dev-master", "fig-r/psr2r-sniffer": "0.*", - "phpdocumentor/phpdocumentor": "2.9.*" + "phpdocumentor/phpdocumentor": "2.*" }, "require": { - "php": "^5.6 || ^7.0" + "php": "^5.6 || ^7.0", + "symfony/process": "3.1.3 as 2.8.9", + "sarehub/commons": "0.*" }, "autoload": { "psr-4": { diff --git a/phpunit.xml b/phpunit.xml index 600126c..abb66ae 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -13,7 +13,7 @@ > - ./unit/tests/ + ./tests/unit/ From 2d301e27edb3bae0afa5708eeafa88a10dbd337b Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Tue, 30 Aug 2016 14:14:39 +0200 Subject: [PATCH 004/133] added CommandInput and stdin for process impl. --- .../ProcessStreamWorkerCommandInput.php | 34 +++++++++++++++++ .../Worker/Command/WorkerCommandInput.php | 17 +++++++++ .../ProcessStreamWorkerCommandInputTest.php | 38 +++++++++++++++++++ 3 files changed, 89 insertions(+) create mode 100644 src/SAREhub/Component/Worker/Command/ProcessStreamWorkerCommandInput.php create mode 100644 src/SAREhub/Component/Worker/Command/WorkerCommandInput.php create mode 100644 tests/unit/SAREhub/Component/Worker/Command/ProcessStreamWorkerCommandInputTest.php diff --git a/src/SAREhub/Component/Worker/Command/ProcessStreamWorkerCommandInput.php b/src/SAREhub/Component/Worker/Command/ProcessStreamWorkerCommandInput.php new file mode 100644 index 0000000..d7b5369 --- /dev/null +++ b/src/SAREhub/Component/Worker/Command/ProcessStreamWorkerCommandInput.php @@ -0,0 +1,34 @@ +inStream = $inStream; + $this->outStream = $outStream; + $this->confirmationString = $confirmationString; + } + + public function getNextCommand() { + $command = trim(fgets($this->inStream)); + if (!empty($command)) { + return WorkerCommand::fromJson($command); + } + + return null; + } + + public function sendCommandConfirmation() { + fwrite($this->outStream, $this->confirmationString); + } +} \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Command/WorkerCommandInput.php b/src/SAREhub/Component/Worker/Command/WorkerCommandInput.php new file mode 100644 index 0000000..04ddf7f --- /dev/null +++ b/src/SAREhub/Component/Worker/Command/WorkerCommandInput.php @@ -0,0 +1,17 @@ +inStream = fopen("php://memory", 'w+'); + $this->outStream = fopen("php://memory", 'w+'); + $this->commandInput = new ProcessStreamWorkerCommandInput($this->inStream, $this->outStream); + } + + public function testGetNextCommandWhenNoCommandSent() { + $this->assertNull($this->commandInput->getNextCommand()); + } + + public function testGetNextCommand() { + $commandParameters = ['testParam' => 1]; + fwrite($this->inStream, json_encode([ + 'name' => 'test', + 'parameters' => $commandParameters + ])."\n"); + + fseek($this->inStream, 0); + $command = $this->commandInput->getNextCommand(); + $this->assertInstanceOf(WorkerCommand::class, $command); + $this->assertEquals('test', $command->getName()); + $this->assertEquals($commandParameters, $command->getParameters()); + } +} From 380d95a6f99b18337c1c5d504cf2b9ecda32178c Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Tue, 30 Aug 2016 14:15:07 +0200 Subject: [PATCH 005/133] added WorkerCommand --- .../Worker/Command/StandardWorkerCommands.php | 23 ++++++++++ .../Worker/Command/WorkerCommand.php | 46 +++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 src/SAREhub/Component/Worker/Command/StandardWorkerCommands.php create mode 100644 src/SAREhub/Component/Worker/Command/WorkerCommand.php diff --git a/src/SAREhub/Component/Worker/Command/StandardWorkerCommands.php b/src/SAREhub/Component/Worker/Command/StandardWorkerCommands.php new file mode 100644 index 0000000..90fb1df --- /dev/null +++ b/src/SAREhub/Component/Worker/Command/StandardWorkerCommands.php @@ -0,0 +1,23 @@ +name = $name; + $this->parameters = ($parameters) ? $parameters : []; + } + + public static function fromJson($json) { + $decoded = json_decode($json, true); + return new self($decoded['name'], $decoded['parameters']); + } + + /** + * @return string + */ + public function getName() { + return $this->name; + } + + /** + * @return array + */ + public function getParameters() { + return $this->parameters; + } + + public function jsonSerialize() { + return [ + 'name' => $this->name, + 'parameters' => $this->parameters + ]; + } +} \ No newline at end of file From 7c337facabea0eee3ffc2cc4534f7601658fd743 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Tue, 30 Aug 2016 14:16:14 +0200 Subject: [PATCH 006/133] added Worker class --- src/SAREhub/Component/Worker/Worker.php | 34 +++++++++++++++++++++ src/SAREhub/Component/Worker/WorkerInfo.php | 19 ++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 src/SAREhub/Component/Worker/Worker.php create mode 100644 src/SAREhub/Component/Worker/WorkerInfo.php diff --git a/src/SAREhub/Component/Worker/Worker.php b/src/SAREhub/Component/Worker/Worker.php new file mode 100644 index 0000000..1c7cf2a --- /dev/null +++ b/src/SAREhub/Component/Worker/Worker.php @@ -0,0 +1,34 @@ +info = $info; + } + + /** + * Implements worker work logic code. + */ + public abstract function work(); + + /** + * Executed when worker was stopped. + * @param array $parameters Optional array with parameters. + */ + public abstract function onStop(array $parameters); + + /** + * @return WorkerInfo + */ + public function getInfo() { + return $this->info; + } +} \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/WorkerInfo.php b/src/SAREhub/Component/Worker/WorkerInfo.php new file mode 100644 index 0000000..7e1977c --- /dev/null +++ b/src/SAREhub/Component/Worker/WorkerInfo.php @@ -0,0 +1,19 @@ + $this->uuid, + 'startTime' => $this->startTime + ]; + } +} \ No newline at end of file From 799e5979d925c247fe7501cc8e0b8b800d8dac69 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Tue, 30 Aug 2016 14:16:42 +0200 Subject: [PATCH 007/133] added WorkerException class --- src/SAREhub/Component/Worker/WorkerException.php | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/SAREhub/Component/Worker/WorkerException.php diff --git a/src/SAREhub/Component/Worker/WorkerException.php b/src/SAREhub/Component/Worker/WorkerException.php new file mode 100644 index 0000000..6b392d2 --- /dev/null +++ b/src/SAREhub/Component/Worker/WorkerException.php @@ -0,0 +1,7 @@ + Date: Tue, 30 Aug 2016 14:48:21 +0200 Subject: [PATCH 008/133] changed Worker class to interface --- src/SAREhub/Component/Worker/Worker.php | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/src/SAREhub/Component/Worker/Worker.php b/src/SAREhub/Component/Worker/Worker.php index 1c7cf2a..542b04e 100644 --- a/src/SAREhub/Component/Worker/Worker.php +++ b/src/SAREhub/Component/Worker/Worker.php @@ -5,30 +5,21 @@ /** * Represents Worker instance. */ -abstract class Worker { - - /** @var WorkerInfo */ - protected $info; - - public function __construct(WorkerInfo $info) { - $this->info = $info; - } +interface Worker { /** - * Implements worker work logic code. + * Executed once on worker start. */ - public abstract function work(); + public function onStart(); /** - * Executed when worker was stopped. - * @param array $parameters Optional array with parameters. + * Executed on every tick, must implements worker logic code. */ - public abstract function onStop(array $parameters); + public function onTick(); /** - * @return WorkerInfo + * Executed when worker was stopped. + * @param array $parameters Optional array with parameters. */ - public function getInfo() { - return $this->info; - } + public function onStop(array $parameters); } \ No newline at end of file From ca4b1fdcf9d353e2308bdb756a3406de049b3b6c Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Tue, 30 Aug 2016 15:11:35 +0200 Subject: [PATCH 009/133] added WorkerRunner class --- src/SAREhub/Component/Worker/WorkerRunner.php | 61 +++++++++++++++++++ .../Component/Worker/WorkerRunnerTest.php | 61 +++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 src/SAREhub/Component/Worker/WorkerRunner.php create mode 100644 tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php diff --git a/src/SAREhub/Component/Worker/WorkerRunner.php b/src/SAREhub/Component/Worker/WorkerRunner.php new file mode 100644 index 0000000..f4ce490 --- /dev/null +++ b/src/SAREhub/Component/Worker/WorkerRunner.php @@ -0,0 +1,61 @@ +worker = $worker; + $this->commandInput = $commandInput; + } + + public function start() { + if (!$this->isRunning()) { + $this->worker->onStart(); + $this->running = true; + } + } + + public function tick() { + if ($this->isRunning()) { + if ($command = $this->commandInput->getNextCommand()) { + $this->processCommand($command); + if (!$this->isRunning()) { + return; + } + } + + $this->worker->onTick(); + } + } + + protected function processCommand(WorkerCommand $command) { + switch ($command->getName()) { + case StandardWorkerCommands::STOP_COMMAND_NAME: + $this->stop($command->getParameters()); + break; + } + } + + public function stop(array $parameters) { + $this->worker->onStop($parameters); + $this->running = false; + } + + public function isRunning() { + return $this->running; + } +} \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php b/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php new file mode 100644 index 0000000..d352ee2 --- /dev/null +++ b/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php @@ -0,0 +1,61 @@ +workerMock = $this->getMockBuilder(Worker::class)->getMock(); + $this->commandInputMock = $this->getMockBuilder(WorkerCommandInput::class)->getMock(); + $this->workerRunner = new WorkerRunner($this->workerMock, $this->commandInputMock); + } + + public function testStart() { + $this->workerMock->expects($this->once())->method('onStart'); + $this->workerRunner->start(); + $this->workerRunner->start(); + $this->assertTrue($this->workerRunner->isRunning()); + } + + public function testTick() { + $this->workerMock->expects($this->once())->method('onTick'); + $this->workerRunner->start(); + $this->commandInputMock->expects($this->once())->method('getNextCommand')->willReturn(null); + $this->workerRunner->tick(); + } + + public function testStop() { + $this->workerMock->expects($this->once())->method('onStop'); + $this->workerRunner->start(); + $this->workerRunner->stop([]); + $this->assertFalse($this->workerRunner->isRunning()); + } + + public function testProcessStopCommand() { + $this->workerMock->expects($this->once())->method('onStop'); + $stopWorkerCommand = $this->getMockBuilder(WorkerCommand::class)->disableOriginalConstructor()->getMock(); + $stopWorkerCommand->method('getName')->willReturn(StandardWorkerCommands::STOP_COMMAND_NAME); + $stopWorkerCommand->method('getParameters')->willReturn([]); + $this->commandInputMock->expects($this->once())->method('getNextCommand')->willReturn($stopWorkerCommand); + + $this->workerRunner->start(); + $this->workerRunner->tick(); + $this->assertFalse($this->workerRunner->isRunning()); + } + +} From bb44713b091914ac50bab2c3e7956396b4a1408f Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Tue, 30 Aug 2016 15:34:02 +0200 Subject: [PATCH 010/133] added WorkerProcess class --- .../Component/Worker/WorkerProcess.php | 73 +++++++++++++++++++ .../Component/Worker/WorkerProcessTest.php | 53 ++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 src/SAREhub/Component/Worker/WorkerProcess.php create mode 100644 tests/unit/SAREhub/Component/Worker/WorkerProcessTest.php diff --git a/src/SAREhub/Component/Worker/WorkerProcess.php b/src/SAREhub/Component/Worker/WorkerProcess.php new file mode 100644 index 0000000..4649fef --- /dev/null +++ b/src/SAREhub/Component/Worker/WorkerProcess.php @@ -0,0 +1,73 @@ +workerInfo = $workerInfo; + $this->workerCommandOutput = $workerCommandOutput; + $this->process = $process; + } + + /** + * Starts worker process. + */ + public function start() { + $this->process->start(); + } + + /** + * @param WorkerCommand $command + * @return string + */ + public function sendCommand(WorkerCommand $command) { + $this->workerCommandOutput->sendCommand($command); + } + + /** + * @return string + */ + public function getLastCommandConfirmation() { + return $this->workerCommandOutput->getCommandConfirmation(); + } + + /** + * Killing process via signal + */ + public function kill() { + $this->process->stop(); + } + + /** + * @return WorkerInfo + */ + public function getWorkerInfo() { + return $this->workerInfo; + } + + /** + * @return Process + */ + public function getProcess() { + return $this->process; + } + + +} \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/WorkerProcessTest.php b/tests/unit/SAREhub/Component/Worker/WorkerProcessTest.php new file mode 100644 index 0000000..1c308a5 --- /dev/null +++ b/tests/unit/SAREhub/Component/Worker/WorkerProcessTest.php @@ -0,0 +1,53 @@ +processMock = $this->getMockBuilder(Process::class)->disableOriginalConstructor()->getMock(); + $this->commandOutputMock = $this->getMockBuilder(WorkerCommandOutput::class)->getMock(); + $this->workerProcess = new WorkerProcess(new WorkerInfo(), $this->commandOutputMock, $this->processMock); + } + + public function testStart() { + $this->processMock->expects($this->once())->method('start'); + $this->workerProcess->start(); + } + + public function testSendCommand() { + $commandMock = $this->getMockBuilder(WorkerCommand::class)->disableOriginalConstructor()->getMock(); + $this->commandOutputMock->expects($this->once()) + ->method('sendCommand') + ->with($this->identicalTo($commandMock)); + $this->workerProcess->sendCommand($commandMock); + } + + public function testGetLastCommandConfirmation() { + $this->commandOutputMock->expects($this->once()) + ->method('getCommandConfirmation')->willReturn('1'); + + $this->assertEquals('1', $this->workerProcess->getLastCommandConfirmation()); + } + + + public function testKill() { + $this->processMock->expects($this->once())->method('stop'); + $this->workerProcess->kill(); + } +} From a28401eb65a57c63e99001ef3b5ed5359eb4fae7 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Tue, 30 Aug 2016 15:39:18 +0200 Subject: [PATCH 011/133] removed parameters from onStop method in Worker interface --- src/SAREhub/Component/Worker/Worker.php | 2 +- src/SAREhub/Component/Worker/WorkerRunner.php | 6 +++--- tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/SAREhub/Component/Worker/Worker.php b/src/SAREhub/Component/Worker/Worker.php index 542b04e..7b73826 100644 --- a/src/SAREhub/Component/Worker/Worker.php +++ b/src/SAREhub/Component/Worker/Worker.php @@ -21,5 +21,5 @@ public function onTick(); * Executed when worker was stopped. * @param array $parameters Optional array with parameters. */ - public function onStop(array $parameters); + public function onStop(); } \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/WorkerRunner.php b/src/SAREhub/Component/Worker/WorkerRunner.php index f4ce490..9b78661 100644 --- a/src/SAREhub/Component/Worker/WorkerRunner.php +++ b/src/SAREhub/Component/Worker/WorkerRunner.php @@ -45,13 +45,13 @@ public function tick() { protected function processCommand(WorkerCommand $command) { switch ($command->getName()) { case StandardWorkerCommands::STOP_COMMAND_NAME: - $this->stop($command->getParameters()); + $this->stop(); break; } } - public function stop(array $parameters) { - $this->worker->onStop($parameters); + public function stop() { + $this->worker->onStop(); $this->running = false; } diff --git a/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php b/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php index d352ee2..d102b4b 100644 --- a/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php +++ b/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php @@ -42,7 +42,7 @@ public function testTick() { public function testStop() { $this->workerMock->expects($this->once())->method('onStop'); $this->workerRunner->start(); - $this->workerRunner->stop([]); + $this->workerRunner->stop(); $this->assertFalse($this->workerRunner->isRunning()); } @@ -50,7 +50,6 @@ public function testProcessStopCommand() { $this->workerMock->expects($this->once())->method('onStop'); $stopWorkerCommand = $this->getMockBuilder(WorkerCommand::class)->disableOriginalConstructor()->getMock(); $stopWorkerCommand->method('getName')->willReturn(StandardWorkerCommands::STOP_COMMAND_NAME); - $stopWorkerCommand->method('getParameters')->willReturn([]); $this->commandInputMock->expects($this->once())->method('getNextCommand')->willReturn($stopWorkerCommand); $this->workerRunner->start(); From 5c5fa4874550bcdcd437073be57c9e0aa8670b16 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Wed, 31 Aug 2016 11:31:35 +0200 Subject: [PATCH 012/133] One command one class --- .../Component/Worker/Command/Command.php | 14 +++++ ...orkerCommandInput.php => CommandInput.php} | 10 ++-- .../Worker/Command/CommandOutput.php | 18 ++++++ .../Command/ProcessStreamCommandInput.php | 39 +++++++++++++ .../Command/ProcessStreamCommandOutput.php | 57 ++++++++++++++----- .../ProcessStreamWorkerCommandInput.php | 34 ----------- .../Standard/KillAllWorkerManagerCommand.php | 15 +++++ .../Command/Standard/KillWorkerCommand.php | 25 ++++++++ .../Command/Standard/StartWorkerCommand.php | 24 ++++++++ .../Command/Standard/StopAllWorkerCommand.php | 14 +++++ .../Command/Standard/StopWorkerCommand.php | 23 ++++++++ .../Worker/Command/StandardWorkerCommands.php | 23 -------- .../Worker/Command/WorkerCommand.php | 39 +------------ .../Worker/Command/WorkerCommandOutput.php | 15 ----- .../Worker/Command/WorkerManagerCommand.php | 8 +++ .../Component/Worker/WorkerProcess.php | 31 ++++------ src/SAREhub/Component/Worker/WorkerRunner.php | 14 ++--- .../ProcessStreamCommandOutputTest.php | 41 +++++++------ .../ProcessStreamWorkerCommandInputTest.php | 31 ++++++---- 19 files changed, 294 insertions(+), 181 deletions(-) create mode 100644 src/SAREhub/Component/Worker/Command/Command.php rename src/SAREhub/Component/Worker/Command/{WorkerCommandInput.php => CommandInput.php} (51%) create mode 100644 src/SAREhub/Component/Worker/Command/CommandOutput.php create mode 100644 src/SAREhub/Component/Worker/Command/ProcessStreamCommandInput.php delete mode 100644 src/SAREhub/Component/Worker/Command/ProcessStreamWorkerCommandInput.php create mode 100644 src/SAREhub/Component/Worker/Command/Standard/KillAllWorkerManagerCommand.php create mode 100644 src/SAREhub/Component/Worker/Command/Standard/KillWorkerCommand.php create mode 100644 src/SAREhub/Component/Worker/Command/Standard/StartWorkerCommand.php create mode 100644 src/SAREhub/Component/Worker/Command/Standard/StopAllWorkerCommand.php create mode 100644 src/SAREhub/Component/Worker/Command/Standard/StopWorkerCommand.php delete mode 100644 src/SAREhub/Component/Worker/Command/StandardWorkerCommands.php delete mode 100644 src/SAREhub/Component/Worker/Command/WorkerCommandOutput.php create mode 100644 src/SAREhub/Component/Worker/Command/WorkerManagerCommand.php diff --git a/src/SAREhub/Component/Worker/Command/Command.php b/src/SAREhub/Component/Worker/Command/Command.php new file mode 100644 index 0000000..6331145 --- /dev/null +++ b/src/SAREhub/Component/Worker/Command/Command.php @@ -0,0 +1,14 @@ +inStream = $inStream; + $this->outStream = $outStream; + $this->replyFormat = $replyFormat; + $this->deserializer = $deserializer; + } + + public function getNextCommand() { + $command = trim(fgets($this->inStream)); + return empty($command) ? null : $this->deserializeCommand($command); + } + + protected function deserializeCommand($command) { + $deserializer = $this->deserializer; + return $deserializer($command); + } + + public function sendCommandReply($reply) { + fwrite($this->outStream, sprintf($this->replyFormat, $reply)); + } +} \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Command/ProcessStreamCommandOutput.php b/src/SAREhub/Component/Worker/Command/ProcessStreamCommandOutput.php index 9a122bc..ac9587a 100644 --- a/src/SAREhub/Component/Worker/Command/ProcessStreamCommandOutput.php +++ b/src/SAREhub/Component/Worker/Command/ProcessStreamCommandOutput.php @@ -4,7 +4,7 @@ use Symfony\Component\Process\Process; -class ProcessStreamCommandOutput implements WorkerCommandOutput { +class ProcessStreamCommandOutput implements CommandOutput { /** @var \resource */ protected $processInputStream; @@ -13,31 +13,60 @@ class ProcessStreamCommandOutput implements WorkerCommandOutput { protected $process; /** @var string */ - protected $confirmationPattern; + protected $processOutput = ''; /** @var string */ - protected $processOutput = ''; + private $replyPattern; + + /**@var callable */ + private $serializer; - public function __construct(Process $process, $confirmationPattern = "1\n") { + /** + * @param Process $process + * @param string $replyPattern Regex pattern for find command reply in process stdout + * @param callable $serializer + */ + public function __construct(Process $process, callable $serializer, $replyPattern = '/###(.+)###/') { $this->processInputStream = $process->getInput(); $this->process = $process; - $this->confirmationPattern = $confirmationPattern; + $this->replyPattern = $replyPattern; + $this->serializer = $serializer; + } + + public function sendCommand(Command $command) { + fwrite($this->processInputStream, $this->serializeCommand($command)."\n"); } - public function sendCommand(WorkerCommand $command) { - fwrite($this->processInputStream, json_encode(($command))."\n"); + /** + * @param Command $command + * @return mixed + */ + protected function serializeCommand(Command $command) { + $serializer = $this->serializer; + return $serializer($command); } - public function getCommandConfirmation() { + public function getCommandReply() { $this->processOutput .= $this->process->getIncrementalOutput(); if (!empty($this->processOutput)) { - $confirmationPos = strpos($this->processOutput, $this->confirmationPattern); - if ($confirmationPos !== false) { - $this->processOutput = substr($this->processOutput, $confirmationPos); - return true; + if ($reply = $this->findReplyPattern()) { + $this->processOutput = substr($this->processOutput, $reply['offset'] + 1); + return $reply['content']; } } - return false; + return null; + } + + protected function findReplyPattern() { + $matches = []; + if (preg_match($this->replyPattern, $this->processOutput, $matches, PREG_OFFSET_CAPTURE)) { + return [ + 'content' => $matches[1][0], + 'offset' => $matches[1][1] + ]; + } + + return null; } -} \ No newline at end of file +} diff --git a/src/SAREhub/Component/Worker/Command/ProcessStreamWorkerCommandInput.php b/src/SAREhub/Component/Worker/Command/ProcessStreamWorkerCommandInput.php deleted file mode 100644 index d7b5369..0000000 --- a/src/SAREhub/Component/Worker/Command/ProcessStreamWorkerCommandInput.php +++ /dev/null @@ -1,34 +0,0 @@ -inStream = $inStream; - $this->outStream = $outStream; - $this->confirmationString = $confirmationString; - } - - public function getNextCommand() { - $command = trim(fgets($this->inStream)); - if (!empty($command)) { - return WorkerCommand::fromJson($command); - } - - return null; - } - - public function sendCommandConfirmation() { - fwrite($this->outStream, $this->confirmationString); - } -} \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Command/Standard/KillAllWorkerManagerCommand.php b/src/SAREhub/Component/Worker/Command/Standard/KillAllWorkerManagerCommand.php new file mode 100644 index 0000000..38d60b3 --- /dev/null +++ b/src/SAREhub/Component/Worker/Command/Standard/KillAllWorkerManagerCommand.php @@ -0,0 +1,15 @@ +uuid = $uuid; + } + + public function getUuid() { + return $this->uuid; + } + + public function getName() { + return self::NAME; + } +} \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Command/Standard/StartWorkerCommand.php b/src/SAREhub/Component/Worker/Command/Standard/StartWorkerCommand.php new file mode 100644 index 0000000..3c1d20a --- /dev/null +++ b/src/SAREhub/Component/Worker/Command/Standard/StartWorkerCommand.php @@ -0,0 +1,24 @@ +uuid = $uuid; + } + + public function getUuid() { + return $this->uuid; + } + + public function getName() { + return self::NAME; + } +} \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Command/Standard/StopAllWorkerCommand.php b/src/SAREhub/Component/Worker/Command/Standard/StopAllWorkerCommand.php new file mode 100644 index 0000000..dcd35bb --- /dev/null +++ b/src/SAREhub/Component/Worker/Command/Standard/StopAllWorkerCommand.php @@ -0,0 +1,14 @@ +uuid = $uuid; + } + + public function getUuid() { + return $this->uuid; + } + + public function getName() { + return self::NAME; + } +} \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Command/StandardWorkerCommands.php b/src/SAREhub/Component/Worker/Command/StandardWorkerCommands.php deleted file mode 100644 index 90fb1df..0000000 --- a/src/SAREhub/Component/Worker/Command/StandardWorkerCommands.php +++ /dev/null @@ -1,23 +0,0 @@ -name = $name; - $this->parameters = ($parameters) ? $parameters : []; - } - - public static function fromJson($json) { - $decoded = json_decode($json, true); - return new self($decoded['name'], $decoded['parameters']); - } +interface WorkerCommand extends Command { /** * @return string */ - public function getName() { - return $this->name; - } - - /** - * @return array - */ - public function getParameters() { - return $this->parameters; - } - - public function jsonSerialize() { - return [ - 'name' => $this->name, - 'parameters' => $this->parameters - ]; - } + public function getUuid(); } \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Command/WorkerCommandOutput.php b/src/SAREhub/Component/Worker/Command/WorkerCommandOutput.php deleted file mode 100644 index a50f5bd..0000000 --- a/src/SAREhub/Component/Worker/Command/WorkerCommandOutput.php +++ /dev/null @@ -1,15 +0,0 @@ -workerInfo = $workerInfo; $this->workerCommandOutput = $workerCommandOutput; $this->process = $process; @@ -34,22 +33,7 @@ public function start() { } /** - * @param WorkerCommand $command - * @return string - */ - public function sendCommand(WorkerCommand $command) { - $this->workerCommandOutput->sendCommand($command); - } - - /** - * @return string - */ - public function getLastCommandConfirmation() { - return $this->workerCommandOutput->getCommandConfirmation(); - } - - /** - * Killing process via signal + * Kills process via signal */ public function kill() { $this->process->stop(); @@ -62,6 +46,13 @@ public function getWorkerInfo() { return $this->workerInfo; } + /** + * @return CommandOutput + */ + public function getCommandOutput() { + return $this->workerCommandOutput; + } + /** * @return Process */ diff --git a/src/SAREhub/Component/Worker/WorkerRunner.php b/src/SAREhub/Component/Worker/WorkerRunner.php index 9b78661..8caf9e3 100644 --- a/src/SAREhub/Component/Worker/WorkerRunner.php +++ b/src/SAREhub/Component/Worker/WorkerRunner.php @@ -2,22 +2,23 @@ namespace SAREhub\Component\Worker; +use SAREhub\Component\Worker\Command\CommandInput; +use SAREhub\Component\Worker\Command\Standard\StopWorkerCommand; use SAREhub\Component\Worker\Command\StandardWorkerCommands; use SAREhub\Component\Worker\Command\WorkerCommand; -use SAREhub\Component\Worker\Command\WorkerCommandInput; class WorkerRunner { /** @var Worker */ protected $worker; - /** @var WorkerCommandInput */ + /** @var CommandInput */ protected $commandInput; /** @var bool */ protected $running = false; - public function __construct(Worker $worker, WorkerCommandInput $commandInput) { + public function __construct(Worker $worker, CommandInput $commandInput) { $this->worker = $worker; $this->commandInput = $commandInput; } @@ -43,10 +44,9 @@ public function tick() { } protected function processCommand(WorkerCommand $command) { - switch ($command->getName()) { - case StandardWorkerCommands::STOP_COMMAND_NAME: - $this->stop(); - break; + if ($command instanceof StopWorkerCommand) { + $this->stop(); + $this->commandInput->sendCommandReply('1'); } } diff --git a/tests/unit/SAREhub/Component/Worker/Command/ProcessStreamCommandOutputTest.php b/tests/unit/SAREhub/Component/Worker/Command/ProcessStreamCommandOutputTest.php index e2be7c2..9d1b3a9 100644 --- a/tests/unit/SAREhub/Component/Worker/Command/ProcessStreamCommandOutputTest.php +++ b/tests/unit/SAREhub/Component/Worker/Command/ProcessStreamCommandOutputTest.php @@ -10,42 +10,51 @@ class ProcessStreamCommandOutputTest extends TestCase { /** @var PHPUnit_Framework_MockObject_MockObject */ private $processMock; + + /** @var \resource */ private $processInputStream; /** @var ProcessStreamCommandOutput */ private $commandOutput; + /** @var PHPUnit_Framework_MockObject_MockObject */ + private $commandMock; + protected function setUp() { $this->processMock = $this->getMockBuilder(Process::class)->disableOriginalConstructor()->getMock(); $this->processInputStream = fopen('php://memory', 'w+'); $this->processMock->method('getInput')->willReturn($this->processInputStream); - $this->commandOutput = new ProcessStreamCommandOutput($this->processMock); + + $this->commandOutput = new ProcessStreamCommandOutput($this->processMock, function (Command $command) { + return json_encode([ + 'name' => $command->getName() + ]); + + }); + + $this->commandMock = $this->getMockBuilder(WorkerCommand::class)->getMock(); + $this->commandMock->method('getName')->willReturn('command'); } public function testSendCommand() { - $commandMock = $this->getMockBuilder(WorkerCommand::class)->disableOriginalConstructor()->getMock(); - $commandMock->expects($this->atLeast(2))->method('jsonSerialize')->willReturn([ - 'name' => 'test', - 'parameters' => [] - ]); - - $this->commandOutput->sendCommand($commandMock); + $this->commandOutput->sendCommand($this->commandMock); fseek($this->processInputStream, 0); - $this->assertEquals(json_encode($commandMock), trim(fgets($this->processInputStream))); + $this->assertEquals(json_encode(['name' => 'command']), trim(fgets($this->processInputStream))); fclose($this->processInputStream); } - public function testGetCommandConfirmation() { - $this->processMock->method('getIncrementalOutput')->willReturn("1\ngfdgdf"); - $this->assertEquals('1', $this->commandOutput->getCommandConfirmation()); + public function testGetCommandReply() { + $this->processMock->method('getIncrementalOutput')->willReturn("###1###"); + $this->assertEquals('1', $this->commandOutput->getCommandReply()); fclose($this->processInputStream); } - public function testGetCommandConfirmationForPartialOutputFromProcess() { - $this->processMock->method('getIncrementalOutput')->willReturnOnConsecutiveCalls("test1", "\nafter", "after"); - $this->assertFalse($this->commandOutput->getCommandConfirmation()); - $this->assertTrue($this->commandOutput->getCommandConfirmation()); + public function testGetCommandReplyForPartialOutputFromProcess() { + $this->processMock->method('getIncrementalOutput')->willReturnOnConsecutiveCalls("test###1", "###\nafter", "after"); + $this->assertNull($this->commandOutput->getCommandReply()); + $this->assertEquals('1', $this->commandOutput->getCommandReply()); + $this->assertNull($this->commandOutput->getCommandReply()); fclose($this->processInputStream); } diff --git a/tests/unit/SAREhub/Component/Worker/Command/ProcessStreamWorkerCommandInputTest.php b/tests/unit/SAREhub/Component/Worker/Command/ProcessStreamWorkerCommandInputTest.php index cd1dc13..090a3ca 100644 --- a/tests/unit/SAREhub/Component/Worker/Command/ProcessStreamWorkerCommandInputTest.php +++ b/tests/unit/SAREhub/Component/Worker/Command/ProcessStreamWorkerCommandInputTest.php @@ -9,13 +9,24 @@ class ProcessStreamWorkerCommandInputTest extends TestCase { private $inStream; private $outStream; - /** @var ProcessStreamWorkerCommandInput */ + /** @var PHPUnit_Framework_MockObject_MockObject */ + private $commandMock; + + /** @var PHPUnit_Framework_MockObject_MockObject */ + private $commandDeserializerMock; + + /** @var ProcessStreamCommandInput */ private $commandInput; protected function setUp() { + $this->commandMock = $this->getMockBuilder(WorkerCommand::class)->getMock(); + $this->commandDeserializerMock = $this->getMockBuilder(\stdClass::class)->setMethods(['__invoke'])->getMock(); + $this->commandDeserializerMock->method('__invoke')->willReturn($this->commandMock); + $this->inStream = fopen("php://memory", 'w+'); $this->outStream = fopen("php://memory", 'w+'); - $this->commandInput = new ProcessStreamWorkerCommandInput($this->inStream, $this->outStream); + $this->commandInput = new ProcessStreamCommandInput($this->inStream, $this->outStream, $this->commandDeserializerMock); + } public function testGetNextCommandWhenNoCommandSent() { @@ -23,16 +34,14 @@ public function testGetNextCommandWhenNoCommandSent() { } public function testGetNextCommand() { - $commandParameters = ['testParam' => 1]; - fwrite($this->inStream, json_encode([ - 'name' => 'test', - 'parameters' => $commandParameters - ])."\n"); + $commandJson = 'testJson'; + $this->commandDeserializerMock->expects($this->once()) + ->method('__invoke') + ->with($commandJson) + ->willReturn($this->commandMock); + fwrite($this->inStream, $commandJson."\n"); fseek($this->inStream, 0); - $command = $this->commandInput->getNextCommand(); - $this->assertInstanceOf(WorkerCommand::class, $command); - $this->assertEquals('test', $command->getName()); - $this->assertEquals($commandParameters, $command->getParameters()); + $this->assertSame($this->commandMock, $this->commandInput->getNextCommand()); } } From e1397c4ee2ffdcb05d44ffbfc65c185875b7b91a Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Wed, 31 Aug 2016 11:32:14 +0200 Subject: [PATCH 013/133] refactored --- src/SAREhub/Component/Worker/Worker.php | 6 +++++- .../Component/Worker/WorkerProcessTest.php | 20 ++----------------- .../Component/Worker/WorkerRunnerTest.php | 9 ++++----- 3 files changed, 11 insertions(+), 24 deletions(-) diff --git a/src/SAREhub/Component/Worker/Worker.php b/src/SAREhub/Component/Worker/Worker.php index 7b73826..faf90dc 100644 --- a/src/SAREhub/Component/Worker/Worker.php +++ b/src/SAREhub/Component/Worker/Worker.php @@ -19,7 +19,11 @@ public function onTick(); /** * Executed when worker was stopped. - * @param array $parameters Optional array with parameters. */ public function onStop(); + + /** + * @return string + */ + public function getUuid(); } \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/WorkerProcessTest.php b/tests/unit/SAREhub/Component/Worker/WorkerProcessTest.php index 1c308a5..d2adc5e 100644 --- a/tests/unit/SAREhub/Component/Worker/WorkerProcessTest.php +++ b/tests/unit/SAREhub/Component/Worker/WorkerProcessTest.php @@ -4,8 +4,7 @@ use PHPUnit\Framework\TestCase; use PHPUnit_Framework_MockObject_MockObject; -use SAREhub\Component\Worker\Command\WorkerCommand; -use SAREhub\Component\Worker\Command\WorkerCommandOutput; +use SAREhub\Component\Worker\Command\CommandOutput; use Symfony\Component\Process\Process; class WorkerProcessTest extends TestCase { @@ -21,7 +20,7 @@ class WorkerProcessTest extends TestCase { protected function setUp() { $this->processMock = $this->getMockBuilder(Process::class)->disableOriginalConstructor()->getMock(); - $this->commandOutputMock = $this->getMockBuilder(WorkerCommandOutput::class)->getMock(); + $this->commandOutputMock = $this->getMockBuilder(CommandOutput::class)->getMock(); $this->workerProcess = new WorkerProcess(new WorkerInfo(), $this->commandOutputMock, $this->processMock); } @@ -30,21 +29,6 @@ public function testStart() { $this->workerProcess->start(); } - public function testSendCommand() { - $commandMock = $this->getMockBuilder(WorkerCommand::class)->disableOriginalConstructor()->getMock(); - $this->commandOutputMock->expects($this->once()) - ->method('sendCommand') - ->with($this->identicalTo($commandMock)); - $this->workerProcess->sendCommand($commandMock); - } - - public function testGetLastCommandConfirmation() { - $this->commandOutputMock->expects($this->once()) - ->method('getCommandConfirmation')->willReturn('1'); - - $this->assertEquals('1', $this->workerProcess->getLastCommandConfirmation()); - } - public function testKill() { $this->processMock->expects($this->once())->method('stop'); diff --git a/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php b/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php index d102b4b..3f5800f 100644 --- a/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php +++ b/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php @@ -4,9 +4,9 @@ use PHPUnit\Framework\TestCase; use PHPUnit_Framework_MockObject_MockObject; +use SAREhub\Component\Worker\Command\CommandInput; +use SAREhub\Component\Worker\Command\Standard\StopWorkerCommand; use SAREhub\Component\Worker\Command\StandardWorkerCommands; -use SAREhub\Component\Worker\Command\WorkerCommand; -use SAREhub\Component\Worker\Command\WorkerCommandInput; class WorkerRunnerTest extends TestCase { @@ -21,7 +21,7 @@ class WorkerRunnerTest extends TestCase { protected function setUp() { $this->workerMock = $this->getMockBuilder(Worker::class)->getMock(); - $this->commandInputMock = $this->getMockBuilder(WorkerCommandInput::class)->getMock(); + $this->commandInputMock = $this->getMockBuilder(CommandInput::class)->getMock(); $this->workerRunner = new WorkerRunner($this->workerMock, $this->commandInputMock); } @@ -48,8 +48,7 @@ public function testStop() { public function testProcessStopCommand() { $this->workerMock->expects($this->once())->method('onStop'); - $stopWorkerCommand = $this->getMockBuilder(WorkerCommand::class)->disableOriginalConstructor()->getMock(); - $stopWorkerCommand->method('getName')->willReturn(StandardWorkerCommands::STOP_COMMAND_NAME); + $stopWorkerCommand = $this->getMockBuilder(StopWorkerCommand::class)->disableOriginalConstructor()->getMock(); $this->commandInputMock->expects($this->once())->method('getNextCommand')->willReturn($stopWorkerCommand); $this->workerRunner->start(); From c10046e24064a9a36d822388a35cab3f59c1803e Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Fri, 2 Sep 2016 12:08:36 +0200 Subject: [PATCH 014/133] refactored to more fluent interface --- .../Component/Worker/Command/CommandInput.php | 5 +- .../Worker/Command/CommandOutput.php | 4 ++ .../Command/ProcessStreamCommandInput.php | 45 ++++++++---- .../Command/ProcessStreamCommandOutput.php | 71 +++++++++++++------ .../ProcessStreamCommandOutputTest.php | 17 +++-- .../ProcessStreamWorkerCommandInputTest.php | 5 +- 6 files changed, 101 insertions(+), 46 deletions(-) diff --git a/src/SAREhub/Component/Worker/Command/CommandInput.php b/src/SAREhub/Component/Worker/Command/CommandInput.php index 261e9a6..26f0463 100644 --- a/src/SAREhub/Component/Worker/Command/CommandInput.php +++ b/src/SAREhub/Component/Worker/Command/CommandInput.php @@ -2,6 +2,9 @@ namespace SAREhub\Component\Worker\Command; +/** + * Represents place from where command can be gets. + */ interface CommandInput { /** @@ -13,7 +16,7 @@ public function getNextCommand(); /** * Sends reply for processed command * @param string $reply - * @return + * @return $this */ public function sendCommandReply($reply); } \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Command/CommandOutput.php b/src/SAREhub/Component/Worker/Command/CommandOutput.php index 7423443..6e4fdd5 100644 --- a/src/SAREhub/Component/Worker/Command/CommandOutput.php +++ b/src/SAREhub/Component/Worker/Command/CommandOutput.php @@ -2,11 +2,15 @@ namespace SAREhub\Component\Worker\Command; +/** + * Represents place for sending commands. + */ interface CommandOutput { /** * Sends command to output. * @param Command $command + * @return $this; */ public function sendCommand(Command $command); diff --git a/src/SAREhub/Component/Worker/Command/ProcessStreamCommandInput.php b/src/SAREhub/Component/Worker/Command/ProcessStreamCommandInput.php index ea4abec..114d81c 100644 --- a/src/SAREhub/Component/Worker/Command/ProcessStreamCommandInput.php +++ b/src/SAREhub/Component/Worker/Command/ProcessStreamCommandInput.php @@ -4,23 +4,42 @@ class ProcessStreamCommandInput implements CommandInput { - /** @var \resource */ - protected $inStream; + const DEFAULT_REPLY_FORMAT = '###%s###'; - /** @var \resource */ + protected $inStream; protected $outStream; + protected $deserializer; + protected $replyFormat; - /** @var string */ - private $replyFormat; - - /** @var callable */ - private $deserializer; - - public function __construct($inStream, $outStream, callable $deserializer, $replyFormat = '###%s###') { + public function __construct($inStream, $outStream) { $this->inStream = $inStream; $this->outStream = $outStream; - $this->replyFormat = $replyFormat; + $this->replyFormat = self::DEFAULT_REPLY_FORMAT; + } + + /** + * @return ProcessStreamCommandInput + */ + public function getForStdIO() { + return new self(STDIN, STDOUT); + } + + /** + * @param callable $deserializer + * @return $this + */ + public function deserializer(callable $deserializer) { $this->deserializer = $deserializer; + return $this; + } + + /** + * @param string $replyFormat + * @return $this + */ + public function replyFormat($replyFormat) { + $this->replyFormat = $replyFormat; + return $this; } public function getNextCommand() { @@ -35,5 +54,7 @@ protected function deserializeCommand($command) { public function sendCommandReply($reply) { fwrite($this->outStream, sprintf($this->replyFormat, $reply)); + return $this; } -} \ No newline at end of file +} + diff --git a/src/SAREhub/Component/Worker/Command/ProcessStreamCommandOutput.php b/src/SAREhub/Component/Worker/Command/ProcessStreamCommandOutput.php index ac9587a..0a45202 100644 --- a/src/SAREhub/Component/Worker/Command/ProcessStreamCommandOutput.php +++ b/src/SAREhub/Component/Worker/Command/ProcessStreamCommandOutput.php @@ -4,46 +4,73 @@ use Symfony\Component\Process\Process; +/** + * Implementation of CommandOutput interface + * Command will be send to selected process stdin + */ class ProcessStreamCommandOutput implements CommandOutput { - /** @var \resource */ - protected $processInputStream; + const DEFAULT_REPLY_PATTERN = '/###(.+)###/'; - /** @var Process */ protected $process; + protected $replyPattern = self::DEFAULT_REPLY_PATTERN; - /** @var string */ + protected $serializer; + protected $processInputStream; protected $processOutput = ''; - /** @var string */ - private $replyPattern; - - /**@var callable */ - private $serializer; - /** + * ProcessStreamCommandOutput constructor. * @param Process $process - * @param string $replyPattern Regex pattern for find command reply in process stdout - * @param callable $serializer */ - public function __construct(Process $process, callable $serializer, $replyPattern = '/###(.+)###/') { - $this->processInputStream = $process->getInput(); + public function __construct(Process $process) { $this->process = $process; - $this->replyPattern = $replyPattern; - $this->serializer = $serializer; + $this->processInputStream = $process->getInput(); + $this->serializer = self::getDefaultSerializer(); } - public function sendCommand(Command $command) { - fwrite($this->processInputStream, $this->serializeCommand($command)."\n"); + /** + * @param Process $process + * @return ProcessStreamCommandOutput + */ + public static function getForProcess(Process $process) { + return new self($process); } /** - * @param Command $command - * @return mixed + * Returns default implementation of command serializer(using Command::__toString method). + * @return \Closure */ - protected function serializeCommand(Command $command) { + public static function getDefaultSerializer() { + return function (Command $command) { + return (string)$command; + }; + } + + /** + * Function for serialize command to send. + * @param callable $serializer + * @return $this + */ + public function serializer(callable $serializer) { + $this->serializer = $serializer; + return $this; + } + + /** + * Regex pattern for find command reply in process output. + * @param string $replyPattern + * @return $this + */ + public function replyPattern($replyPattern) { + $this->replyPattern = $replyPattern; + return $this; + } + + public function sendCommand(Command $command) { $serializer = $this->serializer; - return $serializer($command); + fwrite($this->processInputStream, $serializer($command)."\n"); + return $this; } public function getCommandReply() { diff --git a/tests/unit/SAREhub/Component/Worker/Command/ProcessStreamCommandOutputTest.php b/tests/unit/SAREhub/Component/Worker/Command/ProcessStreamCommandOutputTest.php index 9d1b3a9..b2a36f3 100644 --- a/tests/unit/SAREhub/Component/Worker/Command/ProcessStreamCommandOutputTest.php +++ b/tests/unit/SAREhub/Component/Worker/Command/ProcessStreamCommandOutputTest.php @@ -21,22 +21,21 @@ class ProcessStreamCommandOutputTest extends TestCase { private $commandMock; protected function setUp() { - $this->processMock = $this->getMockBuilder(Process::class)->disableOriginalConstructor()->getMock(); + $this->processMock = $this->createMock(Process::class); $this->processInputStream = fopen('php://memory', 'w+'); $this->processMock->method('getInput')->willReturn($this->processInputStream); - $this->commandOutput = new ProcessStreamCommandOutput($this->processMock, function (Command $command) { - return json_encode([ - 'name' => $command->getName() - ]); - - }); + $this->commandOutput = ProcessStreamCommandOutput::getForProcess($this->processMock) + ->serializer(function (Command $command) { + return json_encode([ + 'name' => $command->getName() + ]); + }); - $this->commandMock = $this->getMockBuilder(WorkerCommand::class)->getMock(); + $this->commandMock = $this->createMock(WorkerCommand::class); $this->commandMock->method('getName')->willReturn('command'); } - public function testSendCommand() { $this->commandOutput->sendCommand($this->commandMock); fseek($this->processInputStream, 0); diff --git a/tests/unit/SAREhub/Component/Worker/Command/ProcessStreamWorkerCommandInputTest.php b/tests/unit/SAREhub/Component/Worker/Command/ProcessStreamWorkerCommandInputTest.php index 090a3ca..ca74cdb 100644 --- a/tests/unit/SAREhub/Component/Worker/Command/ProcessStreamWorkerCommandInputTest.php +++ b/tests/unit/SAREhub/Component/Worker/Command/ProcessStreamWorkerCommandInputTest.php @@ -19,13 +19,14 @@ class ProcessStreamWorkerCommandInputTest extends TestCase { private $commandInput; protected function setUp() { - $this->commandMock = $this->getMockBuilder(WorkerCommand::class)->getMock(); + $this->commandMock = $this->createMock(WorkerCommand::class); $this->commandDeserializerMock = $this->getMockBuilder(\stdClass::class)->setMethods(['__invoke'])->getMock(); $this->commandDeserializerMock->method('__invoke')->willReturn($this->commandMock); $this->inStream = fopen("php://memory", 'w+'); $this->outStream = fopen("php://memory", 'w+'); - $this->commandInput = new ProcessStreamCommandInput($this->inStream, $this->outStream, $this->commandDeserializerMock); + $this->commandInput = new ProcessStreamCommandInput($this->inStream, $this->outStream); + $this->commandInput->deserializer($this->commandDeserializerMock); } From f07bb1f0a543299d7b2256e250c33e0dea512f53 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Fri, 2 Sep 2016 12:08:54 +0200 Subject: [PATCH 015/133] refactored to more fluent interface --- .../Component/Worker/WorkerProcess.php | 33 ++++++++++++------- .../Component/Worker/WorkerProcessTest.php | 3 +- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/SAREhub/Component/Worker/WorkerProcess.php b/src/SAREhub/Component/Worker/WorkerProcess.php index 3ac3f8a..7fbbfec 100644 --- a/src/SAREhub/Component/Worker/WorkerProcess.php +++ b/src/SAREhub/Component/Worker/WorkerProcess.php @@ -10,21 +10,34 @@ */ class WorkerProcess { - /** @var WorkerInfo */ protected $workerInfo; - - /** @var CommandOutput */ - protected $workerCommandOutput; - - /** @var Process */ + protected $commandOutput = null; protected $process; - public function __construct(WorkerInfo $workerInfo, CommandOutput $workerCommandOutput, Process $process) { + protected function __construct(WorkerInfo $workerInfo, Process $process) { $this->workerInfo = $workerInfo; - $this->workerCommandOutput = $workerCommandOutput; $this->process = $process; } + /** + * @param WorkerInfo $workerInfo + * @param Process $process + * @return WorkerProcess + */ + public static function getFor(WorkerInfo $workerInfo, Process $process) { + return new self($workerInfo, $process); + } + + /** + * @param CommandOutput $commandOutput + * @return $this + */ + public function commandOutput(CommandOutput $commandOutput) { + $this->commandOutput = $commandOutput; + return $this; + } + + /** * Starts worker process. */ @@ -50,7 +63,7 @@ public function getWorkerInfo() { * @return CommandOutput */ public function getCommandOutput() { - return $this->workerCommandOutput; + return $this->commandOutput; } /** @@ -59,6 +72,4 @@ public function getCommandOutput() { public function getProcess() { return $this->process; } - - } \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/WorkerProcessTest.php b/tests/unit/SAREhub/Component/Worker/WorkerProcessTest.php index d2adc5e..1c6979a 100644 --- a/tests/unit/SAREhub/Component/Worker/WorkerProcessTest.php +++ b/tests/unit/SAREhub/Component/Worker/WorkerProcessTest.php @@ -21,7 +21,8 @@ class WorkerProcessTest extends TestCase { protected function setUp() { $this->processMock = $this->getMockBuilder(Process::class)->disableOriginalConstructor()->getMock(); $this->commandOutputMock = $this->getMockBuilder(CommandOutput::class)->getMock(); - $this->workerProcess = new WorkerProcess(new WorkerInfo(), $this->commandOutputMock, $this->processMock); + $this->workerProcess = WorkerProcess::getFor(new WorkerInfo(), $this->processMock) + ->commandOutput($this->commandOutputMock); } public function testStart() { From 864b6d637b7f6c63f7a988149c71ec1d49b08559 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Fri, 2 Sep 2016 12:54:10 +0200 Subject: [PATCH 016/133] added WorkerProcessFactory --- .../Component/Worker/WorkerProcessFactory.php | 84 +++++++++++++++++++ .../Worker/WorkerProcessFactoryTest.php | 63 ++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 src/SAREhub/Component/Worker/WorkerProcessFactory.php create mode 100644 tests/unit/SAREhub/Component/Worker/WorkerProcessFactoryTest.php diff --git a/src/SAREhub/Component/Worker/WorkerProcessFactory.php b/src/SAREhub/Component/Worker/WorkerProcessFactory.php new file mode 100644 index 0000000..db2f882 --- /dev/null +++ b/src/SAREhub/Component/Worker/WorkerProcessFactory.php @@ -0,0 +1,84 @@ +runnerScript = $runnerScript; + return $factory; + } + + /** + * Sets working directory for created worker processes. + * @param string $workingDirectory + * @return $this + */ + public function workingDirectory($workingDirectory) { + $this->workingDirectory = (string)$workingDirectory; + return $this; + } + + /** + * @param array $arguments + * @return $this + */ + public function arguments(array $arguments) { + $this->arguments = $arguments; + return $this; + } + + /** + * ```php + * function (Process $process) { + * return $commandOutput; + * } + * ``` + * @param callable $commandOutputFactory + * @return $this + */ + public function commandOutputFactory(callable $commandOutputFactory) { + $this->commandOutputFactory = $commandOutputFactory; + return $this; + } + + /** + * @return \Closure + */ + public static function getDefaultCommandOutputFactory() { + return function (Process $process) { + $process->setInput(new InputStream()); + return ProcessStreamCommandOutput::getForProcess($process); + }; + } + + /** + * @param WorkerInfo $workerInfo + * @return WorkerProcess + */ + public function create(WorkerInfo $workerInfo) { + $processArguments = array_merge(['php', $this->runnerScript], $this->arguments); + $process = ProcessBuilder::create($processArguments) + ->setWorkingDirectory($this->workingDirectory) + ->add($workerInfo->uuid)->getProcess(); + + $commandOutputFactory = $this->commandOutputFactory; + return WorkerProcess::getFor($workerInfo, $process) + ->commandOutput($commandOutputFactory($process)); + } +} \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/WorkerProcessFactoryTest.php b/tests/unit/SAREhub/Component/Worker/WorkerProcessFactoryTest.php new file mode 100644 index 0000000..932bcf5 --- /dev/null +++ b/tests/unit/SAREhub/Component/Worker/WorkerProcessFactoryTest.php @@ -0,0 +1,63 @@ +commandOutputFactoryMock = $this->getMockBuilder(\stdClass::class) + ->setMethods(['__invoke']) + ->getMock(); + + $this->commandOutputMock = $this->createMock(CommandOutput::class); + + $this->commandOutputFactoryMock->expects($this->once()) + ->method('__invoke') + ->with($this->isInstanceOf(Process::class)) + ->willReturn($this->commandOutputMock); + + + $this->factory = WorkerProcessFactory::getForRunnerScript('runner.php') + ->commandOutputFactory($this->commandOutputFactoryMock); + + $this->workerInfo = new WorkerInfo(); + } + + public function testCreate() { + $workerProcess = $this->factory->create($this->workerInfo); + $this->assertSame($this->workerInfo, $workerProcess->getWorkerInfo()); + $this->assertSame($this->commandOutputMock, $workerProcess->getCommandOutput()); + $process = $workerProcess->getProcess(); + $this->assertInstanceOf(Process::class, $process); + $this->assertEquals('"php" "runner.php" ', $process->getCommandLine()); + } + + public function testCreateWithCustomWorkingDirectory() { + $workerProcess = $this->factory->workingDirectory('testdir')->create($this->workerInfo); + $process = $workerProcess->getProcess(); + $this->assertEquals('testdir', $process->getWorkingDirectory()); + } + + public function testCreateWithArguments() { + $workerProcess = $this->factory->arguments(['arg1', 'arg2'])->create($this->workerInfo); + $process = $workerProcess->getProcess(); + $this->assertEquals('"php" "runner.php" "arg1" "arg2" ', $process->getCommandLine()); + } +} From 6072f8d96bc2a1211dbb25c6114d9c0145d25c5f Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Fri, 2 Sep 2016 16:49:38 +0200 Subject: [PATCH 017/133] arguments replaced --- src/SAREhub/Component/Worker/WorkerProcessFactory.php | 5 +++-- .../SAREhub/Component/Worker/WorkerProcessFactoryTest.php | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/SAREhub/Component/Worker/WorkerProcessFactory.php b/src/SAREhub/Component/Worker/WorkerProcessFactory.php index db2f882..a7d79b6 100644 --- a/src/SAREhub/Component/Worker/WorkerProcessFactory.php +++ b/src/SAREhub/Component/Worker/WorkerProcessFactory.php @@ -72,10 +72,11 @@ public static function getDefaultCommandOutputFactory() { * @return WorkerProcess */ public function create(WorkerInfo $workerInfo) { - $processArguments = array_merge(['php', $this->runnerScript], $this->arguments); + $standardArguments = ['php', $this->runnerScript, $workerInfo->uuid]; + $processArguments = array_merge($standardArguments, $this->arguments); $process = ProcessBuilder::create($processArguments) ->setWorkingDirectory($this->workingDirectory) - ->add($workerInfo->uuid)->getProcess(); + ->getProcess(); $commandOutputFactory = $this->commandOutputFactory; return WorkerProcess::getFor($workerInfo, $process) diff --git a/tests/unit/SAREhub/Component/Worker/WorkerProcessFactoryTest.php b/tests/unit/SAREhub/Component/Worker/WorkerProcessFactoryTest.php index 932bcf5..9c680b4 100644 --- a/tests/unit/SAREhub/Component/Worker/WorkerProcessFactoryTest.php +++ b/tests/unit/SAREhub/Component/Worker/WorkerProcessFactoryTest.php @@ -38,6 +38,7 @@ protected function setUp() { ->commandOutputFactory($this->commandOutputFactoryMock); $this->workerInfo = new WorkerInfo(); + $this->workerInfo->uuid = '123'; } public function testCreate() { @@ -46,7 +47,7 @@ public function testCreate() { $this->assertSame($this->commandOutputMock, $workerProcess->getCommandOutput()); $process = $workerProcess->getProcess(); $this->assertInstanceOf(Process::class, $process); - $this->assertEquals('"php" "runner.php" ', $process->getCommandLine()); + $this->assertEquals('"php" "runner.php" "123"', $process->getCommandLine()); } public function testCreateWithCustomWorkingDirectory() { @@ -58,6 +59,6 @@ public function testCreateWithCustomWorkingDirectory() { public function testCreateWithArguments() { $workerProcess = $this->factory->arguments(['arg1', 'arg2'])->create($this->workerInfo); $process = $workerProcess->getProcess(); - $this->assertEquals('"php" "runner.php" "arg1" "arg2" ', $process->getCommandLine()); + $this->assertEquals('"php" "runner.php" "123" "arg1" "arg2"', $process->getCommandLine()); } } From 5a0e7d4638d9b16962e1de46db7d0e2bcc3d870a Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Mon, 5 Sep 2016 10:36:45 +0200 Subject: [PATCH 018/133] refactored to fluent interface --- src/SAREhub/Component/Worker/WorkerInfo.php | 29 +++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/SAREhub/Component/Worker/WorkerInfo.php b/src/SAREhub/Component/Worker/WorkerInfo.php index 7e1977c..145fd7f 100644 --- a/src/SAREhub/Component/Worker/WorkerInfo.php +++ b/src/SAREhub/Component/Worker/WorkerInfo.php @@ -10,6 +10,35 @@ class WorkerInfo { public $uuid; public $startTime; + /** + * @return WorkerInfo + */ + public static function newInfo() { + $info = new self(); + return $info; + } + + /** + * @param string $uuid + * @return $this + */ + public function uuid($uuid) { + $this->uuid = $uuid; + return $this; + } + + /** + * @param string $time + * @return $this + */ + public function startTime($time) { + $this->startTime = $time; + return $this; + } + + /** + * @return array + */ public function toArray() { return [ 'uuid' => $this->uuid, From 5d45fa393dd101957fdd6558bff80bab9471685e Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Mon, 5 Sep 2016 10:37:00 +0200 Subject: [PATCH 019/133] added onCommand method --- src/SAREhub/Component/Worker/Worker.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/SAREhub/Component/Worker/Worker.php b/src/SAREhub/Component/Worker/Worker.php index faf90dc..87efc1c 100644 --- a/src/SAREhub/Component/Worker/Worker.php +++ b/src/SAREhub/Component/Worker/Worker.php @@ -1,6 +1,7 @@ Date: Mon, 5 Sep 2016 10:37:14 +0200 Subject: [PATCH 020/133] refactored --- .../Component/Worker/Command/ProcessStreamCommandInput.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/SAREhub/Component/Worker/Command/ProcessStreamCommandInput.php b/src/SAREhub/Component/Worker/Command/ProcessStreamCommandInput.php index 114d81c..8848877 100644 --- a/src/SAREhub/Component/Worker/Command/ProcessStreamCommandInput.php +++ b/src/SAREhub/Component/Worker/Command/ProcessStreamCommandInput.php @@ -9,18 +9,17 @@ class ProcessStreamCommandInput implements CommandInput { protected $inStream; protected $outStream; protected $deserializer; - protected $replyFormat; + protected $replyFormat = self::DEFAULT_REPLY_FORMAT; public function __construct($inStream, $outStream) { $this->inStream = $inStream; $this->outStream = $outStream; - $this->replyFormat = self::DEFAULT_REPLY_FORMAT; } /** * @return ProcessStreamCommandInput */ - public function getForStdIO() { + public static function getForStdIO() { return new self(STDIN, STDOUT); } From d43160f6a7878f5d7f581891403fd78d5da76c20 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Mon, 5 Sep 2016 14:49:09 +0200 Subject: [PATCH 021/133] added CommandException --- src/SAREhub/Component/Worker/Command/CommandException.php | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 src/SAREhub/Component/Worker/Command/CommandException.php diff --git a/src/SAREhub/Component/Worker/Command/CommandException.php b/src/SAREhub/Component/Worker/Command/CommandException.php new file mode 100644 index 0000000..8f688ca --- /dev/null +++ b/src/SAREhub/Component/Worker/Command/CommandException.php @@ -0,0 +1,8 @@ + Date: Mon, 5 Sep 2016 15:18:35 +0200 Subject: [PATCH 022/133] small fix --- src/SAREhub/Component/Worker/Command/CommandOutput.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SAREhub/Component/Worker/Command/CommandOutput.php b/src/SAREhub/Component/Worker/Command/CommandOutput.php index 6e4fdd5..29cfd1e 100644 --- a/src/SAREhub/Component/Worker/Command/CommandOutput.php +++ b/src/SAREhub/Component/Worker/Command/CommandOutput.php @@ -10,7 +10,7 @@ interface CommandOutput { /** * Sends command to output. * @param Command $command - * @return $this; + * @return $this */ public function sendCommand(Command $command); From ae27240a5a16488b6553a8c36efb73bd5c9bbdbd Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Mon, 5 Sep 2016 15:19:34 +0200 Subject: [PATCH 023/133] removed stdin/stdout command I/O added ZMQ command I/O --- .../Command/ProcessStreamCommandInput.php | 59 ----------- .../Command/ProcessStreamCommandOutput.php | 99 ------------------- .../Worker/Command/ZmqCommandInput.php | 83 ++++++++++++++++ .../Worker/Command/ZmqCommandOutput.php | 64 ++++++++++++ .../ProcessStreamCommandOutputTest.php | 61 ------------ .../ProcessStreamWorkerCommandInputTest.php | 48 --------- .../Worker/Command/ZmqCommandInputTest.php | 77 +++++++++++++++ .../Worker/Command/ZmqCommandOutputTest.php | 75 ++++++++++++++ 8 files changed, 299 insertions(+), 267 deletions(-) delete mode 100644 src/SAREhub/Component/Worker/Command/ProcessStreamCommandInput.php delete mode 100644 src/SAREhub/Component/Worker/Command/ProcessStreamCommandOutput.php create mode 100644 src/SAREhub/Component/Worker/Command/ZmqCommandInput.php create mode 100644 src/SAREhub/Component/Worker/Command/ZmqCommandOutput.php delete mode 100644 tests/unit/SAREhub/Component/Worker/Command/ProcessStreamCommandOutputTest.php delete mode 100644 tests/unit/SAREhub/Component/Worker/Command/ProcessStreamWorkerCommandInputTest.php create mode 100644 tests/unit/SAREhub/Component/Worker/Command/ZmqCommandInputTest.php create mode 100644 tests/unit/SAREhub/Component/Worker/Command/ZmqCommandOutputTest.php diff --git a/src/SAREhub/Component/Worker/Command/ProcessStreamCommandInput.php b/src/SAREhub/Component/Worker/Command/ProcessStreamCommandInput.php deleted file mode 100644 index 8848877..0000000 --- a/src/SAREhub/Component/Worker/Command/ProcessStreamCommandInput.php +++ /dev/null @@ -1,59 +0,0 @@ -inStream = $inStream; - $this->outStream = $outStream; - } - - /** - * @return ProcessStreamCommandInput - */ - public static function getForStdIO() { - return new self(STDIN, STDOUT); - } - - /** - * @param callable $deserializer - * @return $this - */ - public function deserializer(callable $deserializer) { - $this->deserializer = $deserializer; - return $this; - } - - /** - * @param string $replyFormat - * @return $this - */ - public function replyFormat($replyFormat) { - $this->replyFormat = $replyFormat; - return $this; - } - - public function getNextCommand() { - $command = trim(fgets($this->inStream)); - return empty($command) ? null : $this->deserializeCommand($command); - } - - protected function deserializeCommand($command) { - $deserializer = $this->deserializer; - return $deserializer($command); - } - - public function sendCommandReply($reply) { - fwrite($this->outStream, sprintf($this->replyFormat, $reply)); - return $this; - } -} - diff --git a/src/SAREhub/Component/Worker/Command/ProcessStreamCommandOutput.php b/src/SAREhub/Component/Worker/Command/ProcessStreamCommandOutput.php deleted file mode 100644 index 0a45202..0000000 --- a/src/SAREhub/Component/Worker/Command/ProcessStreamCommandOutput.php +++ /dev/null @@ -1,99 +0,0 @@ -process = $process; - $this->processInputStream = $process->getInput(); - $this->serializer = self::getDefaultSerializer(); - } - - /** - * @param Process $process - * @return ProcessStreamCommandOutput - */ - public static function getForProcess(Process $process) { - return new self($process); - } - - /** - * Returns default implementation of command serializer(using Command::__toString method). - * @return \Closure - */ - public static function getDefaultSerializer() { - return function (Command $command) { - return (string)$command; - }; - } - - /** - * Function for serialize command to send. - * @param callable $serializer - * @return $this - */ - public function serializer(callable $serializer) { - $this->serializer = $serializer; - return $this; - } - - /** - * Regex pattern for find command reply in process output. - * @param string $replyPattern - * @return $this - */ - public function replyPattern($replyPattern) { - $this->replyPattern = $replyPattern; - return $this; - } - - public function sendCommand(Command $command) { - $serializer = $this->serializer; - fwrite($this->processInputStream, $serializer($command)."\n"); - return $this; - } - - public function getCommandReply() { - $this->processOutput .= $this->process->getIncrementalOutput(); - if (!empty($this->processOutput)) { - if ($reply = $this->findReplyPattern()) { - $this->processOutput = substr($this->processOutput, $reply['offset'] + 1); - return $reply['content']; - } - } - - return null; - } - - protected function findReplyPattern() { - $matches = []; - if (preg_match($this->replyPattern, $this->processOutput, $matches, PREG_OFFSET_CAPTURE)) { - return [ - 'content' => $matches[1][0], - 'offset' => $matches[1][1] - ]; - } - - return null; - } -} diff --git a/src/SAREhub/Component/Worker/Command/ZmqCommandInput.php b/src/SAREhub/Component/Worker/Command/ZmqCommandInput.php new file mode 100644 index 0000000..0e75a4f --- /dev/null +++ b/src/SAREhub/Component/Worker/Command/ZmqCommandInput.php @@ -0,0 +1,83 @@ +commandReceiver = $commandReceiver; + } + + /** + * @param RequestReceiver $commandReceiver + * @return ZmqCommandInput + */ + public static function forReceiver(RequestReceiver $commandReceiver) { + return new self($commandReceiver); + } + + /** + * @return $this + */ + public function blockingMode() { + $this->blockingMode = true; + return $this; + } + + /** + * @return $this + */ + public function nonBlockingMode() { + $this->blockingMode = false; + return $this; + } + + /** + * @param callable $deserializer + * @return $this + */ + public function deserializer(callable $deserializer) { + $this->deserializer = $deserializer; + return $this; + } + + public function getNextCommand() { + if ($commandData = $this->commandReceiver->receiveRequest($this->isInBlockingMode())) { + $deserializer = $this->deserializer; + $command = $deserializer($commandData); + if ($command instanceof Command) { + return $command; + } + + throw new CommandException("Deserializer must return Command instance: ".$command); + } + + return null; + } + + public function sendCommandReply($reply) { + $this->commandReceiver->sendReply($reply, $this->isInBlockingMode()); + return $this; + } + + /** + * @return bool + */ + public function isInBlockingMode() { + return $this->blockingMode; + } +} \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Command/ZmqCommandOutput.php b/src/SAREhub/Component/Worker/Command/ZmqCommandOutput.php new file mode 100644 index 0000000..c489c89 --- /dev/null +++ b/src/SAREhub/Component/Worker/Command/ZmqCommandOutput.php @@ -0,0 +1,64 @@ +commandSender = $commandSender; + } + + /** + * @param RequestSender $commandSender + * @return ZmqCommandOutput + */ + public static function forSender(RequestSender $commandSender) { + return new self($commandSender); + } + + /** + * @return $this + */ + public function blockingMode() { + $this->blockingMode = true; + return $this; + } + + /** + * @return $this + */ + public function nonBlockingMode() { + $this->blockingMode = true; + return $this; + } + + /** + * @param callable $serializer + * @return $this + */ + public function serializer(callable $serializer) { + $this->serializer = $serializer; + return $this; + } + + public function sendCommand(Command $command) { + $serializer = $this->serializer; + $this->commandSender->sendRequest($serializer($command), $this->isInBlockingMode()); + return $this; + } + + public function getCommandReply() { + return $this->commandSender->receiveReply($this->isInBlockingMode()); + } + + public function isInBlockingMode() { + return $this->blockingMode; + } +} \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Command/ProcessStreamCommandOutputTest.php b/tests/unit/SAREhub/Component/Worker/Command/ProcessStreamCommandOutputTest.php deleted file mode 100644 index b2a36f3..0000000 --- a/tests/unit/SAREhub/Component/Worker/Command/ProcessStreamCommandOutputTest.php +++ /dev/null @@ -1,61 +0,0 @@ -processMock = $this->createMock(Process::class); - $this->processInputStream = fopen('php://memory', 'w+'); - $this->processMock->method('getInput')->willReturn($this->processInputStream); - - $this->commandOutput = ProcessStreamCommandOutput::getForProcess($this->processMock) - ->serializer(function (Command $command) { - return json_encode([ - 'name' => $command->getName() - ]); - }); - - $this->commandMock = $this->createMock(WorkerCommand::class); - $this->commandMock->method('getName')->willReturn('command'); - } - - public function testSendCommand() { - $this->commandOutput->sendCommand($this->commandMock); - fseek($this->processInputStream, 0); - $this->assertEquals(json_encode(['name' => 'command']), trim(fgets($this->processInputStream))); - fclose($this->processInputStream); - } - - public function testGetCommandReply() { - $this->processMock->method('getIncrementalOutput')->willReturn("###1###"); - $this->assertEquals('1', $this->commandOutput->getCommandReply()); - fclose($this->processInputStream); - } - - public function testGetCommandReplyForPartialOutputFromProcess() { - $this->processMock->method('getIncrementalOutput')->willReturnOnConsecutiveCalls("test###1", "###\nafter", "after"); - $this->assertNull($this->commandOutput->getCommandReply()); - $this->assertEquals('1', $this->commandOutput->getCommandReply()); - $this->assertNull($this->commandOutput->getCommandReply()); - fclose($this->processInputStream); - } - - -} diff --git a/tests/unit/SAREhub/Component/Worker/Command/ProcessStreamWorkerCommandInputTest.php b/tests/unit/SAREhub/Component/Worker/Command/ProcessStreamWorkerCommandInputTest.php deleted file mode 100644 index ca74cdb..0000000 --- a/tests/unit/SAREhub/Component/Worker/Command/ProcessStreamWorkerCommandInputTest.php +++ /dev/null @@ -1,48 +0,0 @@ -commandMock = $this->createMock(WorkerCommand::class); - $this->commandDeserializerMock = $this->getMockBuilder(\stdClass::class)->setMethods(['__invoke'])->getMock(); - $this->commandDeserializerMock->method('__invoke')->willReturn($this->commandMock); - - $this->inStream = fopen("php://memory", 'w+'); - $this->outStream = fopen("php://memory", 'w+'); - $this->commandInput = new ProcessStreamCommandInput($this->inStream, $this->outStream); - $this->commandInput->deserializer($this->commandDeserializerMock); - - } - - public function testGetNextCommandWhenNoCommandSent() { - $this->assertNull($this->commandInput->getNextCommand()); - } - - public function testGetNextCommand() { - $commandJson = 'testJson'; - $this->commandDeserializerMock->expects($this->once()) - ->method('__invoke') - ->with($commandJson) - ->willReturn($this->commandMock); - - fwrite($this->inStream, $commandJson."\n"); - fseek($this->inStream, 0); - $this->assertSame($this->commandMock, $this->commandInput->getNextCommand()); - } -} diff --git a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandInputTest.php b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandInputTest.php new file mode 100644 index 0000000..371f016 --- /dev/null +++ b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandInputTest.php @@ -0,0 +1,77 @@ +receiverMock = $this->createMock(RequestReceiver::class); + $this->deserializerMock = $this->getMockBuilder(\stdClass::class)->setMethods(['__invoke'])->getMock(); + $this->commandMock = $this->createMock(Command::class); + $this->deserializerMock->method('__invoke')->willReturn($this->commandMock); + + $this->commandInput = ZmqCommandInput::forReceiver($this->receiverMock) + ->deserializer($this->deserializerMock); + } + + public function testGetNextCommand() { + $this->receiverMock->expects($this->once()) + ->method('receiveRequest') + ->with(false) + ->willReturn("command"); + $this->deserializerMock->expects($this->once()) + ->method('__invoke') + ->with('command') + ->willReturn($this->commandMock); + $this->assertSame($this->commandMock, $this->commandInput->getNextCommand()); + } + + public function testGetNextCommandBlocking() { + $this->receiverMock->expects($this->once()) + ->method('receiveRequest') + ->with(true) + ->willReturn("command"); + $this->deserializerMock->expects($this->once()) + ->method('__invoke') + ->with('command') + ->willReturn($this->commandMock); + $this->assertSame($this->commandMock, $this->commandInput->blockingMode()->getNextCommand()); + } + + public function testGetNextCommandWhenNotSent() { + $this->receiverMock->expects($this->once())->method('receiveRequest')->with(false)->willReturn(false); + $this->assertNull($this->commandInput->getNextCommand()); + } + + public function testSendReply() { + $this->receiverMock->expects($this->once()) + ->method('sendReply') + ->with('reply', false) + ->willReturn($this->receiverMock); + $this->commandInput->sendCommandReply('reply'); + } + + public function testSendReplyBlocking() { + $this->receiverMock->expects($this->once()) + ->method('sendReply') + ->with('reply', true) + ->willReturn($this->receiverMock); + $this->commandInput->blockingMode()->sendCommandReply('reply'); + } +} diff --git a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandOutputTest.php b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandOutputTest.php new file mode 100644 index 0000000..3a895d6 --- /dev/null +++ b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandOutputTest.php @@ -0,0 +1,75 @@ +senderMock = $this->createMock(RequestSender::class); + $this->serializerMock = $this->getMockBuilder(\stdClass::class) + ->setMethods(['__invoke']) + ->getMock(); + $this->commandMock = $this->createMock(Command::class); + + + $this->commandOutput = ZmqCommandOutput::forSender($this->senderMock) + ->serializer($this->serializerMock); + } + + public function testSendCommand() { + $this->senderMock->expects($this->once()) + ->method('sendRequest') + ->with('command', false); + + $this->serializerMock->expects($this->once()) + ->method('__invoke') + ->with($this->commandMock) + ->willReturn("command"); + $this->assertSame($this->commandOutput, $this->commandOutput->sendCommand($this->commandMock)); + } + + public function testSendBlocking() { + $this->senderMock->expects($this->once()) + ->method('sendRequest') + ->with('command', true); + + $this->serializerMock->expects($this->once()) + ->method('__invoke') + ->with($this->commandMock) + ->willReturn("command"); + $this->assertSame($this->commandOutput, $this->commandOutput->blockingMode() + ->sendCommand($this->commandMock)); + } + + public function testGetCommandReply() { + $this->senderMock->expects($this->once()) + ->method('receiveReply') + ->with(false) + ->willReturn('reply'); + $this->assertEquals('reply', $this->commandOutput->getCommandReply()); + } + + public function testGetCommandReplyBlocking() { + $this->senderMock->expects($this->once()) + ->method('receiveReply') + ->with(true) + ->willReturn('reply'); + $this->assertEquals('reply', $this->commandOutput->blockingMode()->getCommandReply()); + } +} From aa294f70f09c34cc092e517a02e217976848c350 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Mon, 5 Sep 2016 15:20:07 +0200 Subject: [PATCH 024/133] fixed --- .../Component/Worker/WorkerManager.php | 208 ++++++++++++++++++ .../Component/Worker/WorkerProcess.php | 7 + .../Component/Worker/WorkerProcessFactory.php | 2 +- src/SAREhub/Component/Worker/WorkerRunner.php | 76 +++++-- .../Component/Worker/WorkerManagerTest.php | 66 ++++++ .../Component/Worker/WorkerRunnerTest.php | 6 +- 6 files changed, 348 insertions(+), 17 deletions(-) create mode 100644 src/SAREhub/Component/Worker/WorkerManager.php create mode 100644 tests/unit/SAREhub/Component/Worker/WorkerManagerTest.php diff --git a/src/SAREhub/Component/Worker/WorkerManager.php b/src/SAREhub/Component/Worker/WorkerManager.php new file mode 100644 index 0000000..e6c559f --- /dev/null +++ b/src/SAREhub/Component/Worker/WorkerManager.php @@ -0,0 +1,208 @@ +uuid = $uuid; + } + + /** + * @param string $uuid + * @return WorkerManager + */ + public static function getNewWithUuid($uuid) { + return new self($uuid); + } + + /** + * @param CommandInput $commandInput + * @return $this + */ + public function commandInput(CommandInput $commandInput) { + $this->commandInput = $commandInput; + return $this; + } + + /** + * @param WorkerProcessFactory $factory + * @return $this + */ + public function workerProcessFactory(WorkerProcessFactory $factory) { + $this->workerProcessFactory = $factory; + return $this; + } + + public function onStart() { + + } + + public function onTick() { + if ($this->checkCommandReply()) { + if ($command = $this->commandInput->getNextCommand()) { + $this->processCommand($command); + } + } + } + + public function processCommand(Command $command) { + if ($command instanceof StartWorkerCommand) { + $this->startWorker($command->getUuid()); + $this->commandInput->sendCommandReply('1'); + return; + } + + if ($command instanceof StopWorkerCommand) { + $this->stopWorker($command->getUuid()); + return; + } + + throw new WorkerException('Unknown command: '.$command->getName()); + } + + /** + * Starting new worker process + * @param string $uuid + * @throws WorkerException + */ + public function startWorker($uuid) { + if ($this->hasWorkerProcess($uuid)) { + throw new WorkerException('Worker with that uuid is running: '.$uuid); + } + + $this->workerProcessList[$uuid] = $this->workerProcessFactory->create( + WorkerInfo::newInfo() + ->uuid($uuid) + ->startTime(time()) + ); + + $this->workerProcessList[$uuid]->start(); + } + + /** + * Stops all running workers + */ + public function stopAll() { + foreach ($this->workerProcessList as $uuid => $workerProcess) { + $this->stopWorker($uuid); + } + } + + public function stopWorker($uuid) { + if ($this->hasWorkerProcess($uuid)) { + $workerProcess = $this->getWorkerProcess($uuid); + $workerProcess->getCommandOutput()->sendCommand(new StopWorkerCommand($uuid)); + $this->waitingCommandReplyProcess = $workerProcess; + } + + } + + public function killAll() { + foreach ($this->workerProcessList as $uuid => $workerProcess) { + $this->killWorker($uuid); + } + } + + public function killWorker($uuid) { + if ($this->hasWorkerProcess($uuid)) { + $workerProcess = $this->getWorkerProcess($uuid); + $workerProcess->kill(); + } + } + + /** + * @param string $uuid + * @return WorkerProcess + */ + public function getWorkerProcess($uuid) { + return $this->workerProcessList[$uuid]; + } + + /** + * @return WorkerProcess[] + */ + public function getWorkerProcessList() { + return $this->workerProcessList; + } + + /** + * @param string $uuid + * @return bool + */ + public function hasWorkerProcess($uuid) { + return isset($this->workerProcessList[$uuid]); + } + + protected function checkCommandReply() { + if ($this->waitingCommandReplyProcess) { + $workerCommandOutput = $this->waitingCommandReplyProcess->getCommandOutput(); + if ($reply = $workerCommandOutput->getCommandReply()) { + $this->getCommandInput()->sendCommandReply($reply); + $this->waitingCommandReplyProcess = null; + } + return false; + } + + return true; + } + + public function isWaitingForCommandReplyFromWorker() { + return $this->waitingCommandReplyProcess != null; + } + + public function checkWorkersHealth() { + foreach ($this->workerProcessList as $workerProcess) { + if ($workerProcess->getProcess()->isRunning()) { + + } + } + } + + public function onStop() { + $this->stopAll(); + } + + public function onCommand(WorkerCommand $command) { + + } + + public function getUuid() { + return $this->uuid; + } + + /** + * @return CommandInput + */ + public function getCommandInput() { + return $this->commandInput; + } + +} \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/WorkerProcess.php b/src/SAREhub/Component/Worker/WorkerProcess.php index 7fbbfec..c40aa6c 100644 --- a/src/SAREhub/Component/Worker/WorkerProcess.php +++ b/src/SAREhub/Component/Worker/WorkerProcess.php @@ -59,6 +59,13 @@ public function getWorkerInfo() { return $this->workerInfo; } + /** + * @return string + */ + public function getWorkerUuid() { + return $this->workerInfo->uuid; + } + /** * @return CommandOutput */ diff --git a/src/SAREhub/Component/Worker/WorkerProcessFactory.php b/src/SAREhub/Component/Worker/WorkerProcessFactory.php index a7d79b6..314a287 100644 --- a/src/SAREhub/Component/Worker/WorkerProcessFactory.php +++ b/src/SAREhub/Component/Worker/WorkerProcessFactory.php @@ -21,7 +21,7 @@ class WorkerProcessFactory { public static function getForRunnerScript($runnerScript) { $factory = new self(); $factory->runnerScript = $runnerScript; - return $factory; + return $factory->commandOutputFactory(self::getDefaultCommandOutputFactory()); } /** diff --git a/src/SAREhub/Component/Worker/WorkerRunner.php b/src/SAREhub/Component/Worker/WorkerRunner.php index 8caf9e3..f4582ee 100644 --- a/src/SAREhub/Component/Worker/WorkerRunner.php +++ b/src/SAREhub/Component/Worker/WorkerRunner.php @@ -5,8 +5,10 @@ use SAREhub\Component\Worker\Command\CommandInput; use SAREhub\Component\Worker\Command\Standard\StopWorkerCommand; use SAREhub\Component\Worker\Command\StandardWorkerCommands; -use SAREhub\Component\Worker\Command\WorkerCommand; +/** + * Helper class for run worker. + */ class WorkerRunner { /** @var Worker */ @@ -18,11 +20,40 @@ class WorkerRunner { /** @var bool */ protected $running = false; - public function __construct(Worker $worker, CommandInput $commandInput) { + public function __construct(Worker $worker) { $this->worker = $worker; + } + + /** + * @param Worker $worker + * @return WorkerRunner + */ + public static function wrap(Worker $worker) { + return new self($worker); + } + + /** + * @param CommandInput $commandInput + * @return $this + */ + public function commandInput(CommandInput $commandInput) { $this->commandInput = $commandInput; + return $this; + } + + /** + * Starts worker loop. + */ + public function run() { + $this->start(); + while ($this->isRunning()) { + $this->tick(); + } } + /** + * Calls once on worker start. + */ public function start() { if (!$this->isRunning()) { $this->worker->onStart(); @@ -30,32 +61,51 @@ public function start() { } } + /** + * Calls per main loop tick. + */ public function tick() { + $this->checkCommand(); if ($this->isRunning()) { - if ($command = $this->commandInput->getNextCommand()) { - $this->processCommand($command); - if (!$this->isRunning()) { - return; - } - } - $this->worker->onTick(); } } - protected function processCommand(WorkerCommand $command) { - if ($command instanceof StopWorkerCommand) { - $this->stop(); - $this->commandInput->sendCommandReply('1'); + protected function checkCommand() { + if ($command = $this->commandInput->getNextCommand()) { + if ($command instanceof StopWorkerCommand) { + $this->stop(); + $this->commandInput->sendCommandReply('1'); + } } } + /** + * Stop worker process + */ public function stop() { $this->worker->onStop(); $this->running = false; } + /** + * @return bool + */ public function isRunning() { return $this->running; } + + /** + * @return Worker + */ + public function getWorker() { + return $this->worker; + } + + /** + * @return CommandInput + */ + public function getCommandInput() { + return $this->commandInput; + } } \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/WorkerManagerTest.php b/tests/unit/SAREhub/Component/Worker/WorkerManagerTest.php new file mode 100644 index 0000000..1d280d0 --- /dev/null +++ b/tests/unit/SAREhub/Component/Worker/WorkerManagerTest.php @@ -0,0 +1,66 @@ +workerProcessMock = $this->createMock(WorkerProcess::class); + $this->workerProcessMock->method('getWorkerUuid')->willReturn($this->workerUuid); + $this->workerCommandOutputMock = $this->createMock(CommandOutput::class); + $this->workerProcessMock->method('getCommandOutput')->willReturn($this->workerCommandOutputMock); + + $this->workerProcessFactoryMock = $this->createMock(WorkerProcessFactory::class); + $this->workerProcessFactoryMock->method('create')->willReturn($this->workerProcessMock); + $this->commandInputMock = $this->createMock(CommandInput::class); + $this->workerManager = WorkerManager::getNewWithUuid('manager') + ->workerProcessFactory($this->workerProcessFactoryMock); + } + + public function testStartWorker() { + $this->workerProcessFactoryMock->expects($this->once()) + ->method('create')->with($this->isInstanceOf(WorkerInfo::class)) + ->willReturn($this->workerProcessMock); + $this->workerProcessMock->expects($this->once())->method('start'); + $this->workerManager->startWorker($this->workerUuid); + $this->assertEquals([ + $this->workerUuid => $this->workerProcessMock + ], $this->workerManager->getWorkerProcessList()); + } + + public function testStopWorker() { + $this->workerManager->startWorker($this->workerUuid); + $this->workerCommandOutputMock->expects($this->once()) + ->method('sendCommand') + ->with(new StopWorkerCommand($this->workerUuid)); + + $this->assertFalse($this->workerManager->isWaitingForCommandReplyFromWorker()); + $this->workerManager->stopWorker($this->workerUuid); + $this->assertTrue($this->workerManager->isWaitingForCommandReplyFromWorker()); + } +} diff --git a/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php b/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php index 3f5800f..b7da8a0 100644 --- a/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php +++ b/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php @@ -20,9 +20,9 @@ class WorkerRunnerTest extends TestCase { private $workerRunner; protected function setUp() { - $this->workerMock = $this->getMockBuilder(Worker::class)->getMock(); - $this->commandInputMock = $this->getMockBuilder(CommandInput::class)->getMock(); - $this->workerRunner = new WorkerRunner($this->workerMock, $this->commandInputMock); + $this->workerMock = $this->createMock(Worker::class); + $this->commandInputMock = $this->createMock(CommandInput::class); + $this->workerRunner = WorkerRunner::wrap($this->workerMock)->commandInput($this->commandInputMock); } public function testStart() { From 72301cdc878765bdb71bb69c7ebb34291af1631e Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Wed, 5 Oct 2016 10:54:13 +0200 Subject: [PATCH 025/133] added BasicCommand --- .../Component/Worker/Command/BasicCommand.php | 31 +++++++++++++++++++ .../Worker/Command/WorkerManagerCommand.php | 8 ----- .../Worker/Command/BasicCommandTest.php | 22 +++++++++++++ 3 files changed, 53 insertions(+), 8 deletions(-) create mode 100644 src/SAREhub/Component/Worker/Command/BasicCommand.php delete mode 100644 src/SAREhub/Component/Worker/Command/WorkerManagerCommand.php create mode 100644 tests/unit/SAREhub/Component/Worker/Command/BasicCommandTest.php diff --git a/src/SAREhub/Component/Worker/Command/BasicCommand.php b/src/SAREhub/Component/Worker/Command/BasicCommand.php new file mode 100644 index 0000000..08d65db --- /dev/null +++ b/src/SAREhub/Component/Worker/Command/BasicCommand.php @@ -0,0 +1,31 @@ +name = $name; + $this->parameters = empty($parameters) ? [] : $parameters; + } + + /** + * @return string + */ + public function getName() { + return $this->name; + } + + /** + * @return array + */ + public function getParameters() { + return $this->parameters; + } +} \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Command/WorkerManagerCommand.php b/src/SAREhub/Component/Worker/Command/WorkerManagerCommand.php deleted file mode 100644 index 7a8ed25..0000000 --- a/src/SAREhub/Component/Worker/Command/WorkerManagerCommand.php +++ /dev/null @@ -1,8 +0,0 @@ -assertEquals('name', $command->getName()); + $this->assertEquals([], $command->getParameters()); + } + + public function testCreateWithParameters() { + $parameters = ['param1' => 1]; + $command = new BasicCommand('name', $parameters); + $this->assertEquals('name', $command->getName()); + $this->assertEquals($parameters, $command->getParameters()); + } +} From 7ff62cdcd9633a6a71cb76dff3dfe9f70c4d5ab8 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Wed, 5 Oct 2016 10:54:28 +0200 Subject: [PATCH 026/133] added Command interface --- src/SAREhub/Component/Worker/Command/Command.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/SAREhub/Component/Worker/Command/Command.php b/src/SAREhub/Component/Worker/Command/Command.php index 6331145..247bfb9 100644 --- a/src/SAREhub/Component/Worker/Command/Command.php +++ b/src/SAREhub/Component/Worker/Command/Command.php @@ -11,4 +11,9 @@ interface Command { * @return string */ public function getName(); + + /** + * @return array + */ + public function getParameters(); } \ No newline at end of file From 44acf101e81de3d3f1acfea2e8b16e5b375d2c8f Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Wed, 5 Oct 2016 11:08:39 +0200 Subject: [PATCH 027/133] added CommandFormat with Json impl. --- .../Worker/Command/CommandFormat.php | 18 ++++++++++ .../Worker/Command/JsonCommandFormat.php | 31 ++++++++++++++++ .../Worker/Command/JsonCommandFormatTest.php | 35 +++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 src/SAREhub/Component/Worker/Command/CommandFormat.php create mode 100644 src/SAREhub/Component/Worker/Command/JsonCommandFormat.php create mode 100644 tests/unit/SAREhub/Component/Worker/Command/JsonCommandFormatTest.php diff --git a/src/SAREhub/Component/Worker/Command/CommandFormat.php b/src/SAREhub/Component/Worker/Command/CommandFormat.php new file mode 100644 index 0000000..99f7fa7 --- /dev/null +++ b/src/SAREhub/Component/Worker/Command/CommandFormat.php @@ -0,0 +1,18 @@ + $command->getName(), + self::PARAMETERS_INDEX => $command->getParameters() + ]); + } + + public function unmarshal($commandData) { + $commandData = json_decode($commandData, true); + return new BasicCommand($commandData[self::NAME_INDEX], $commandData[self::PARAMETERS_INDEX]); + } +} \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Command/JsonCommandFormatTest.php b/tests/unit/SAREhub/Component/Worker/Command/JsonCommandFormatTest.php new file mode 100644 index 0000000..f840f89 --- /dev/null +++ b/tests/unit/SAREhub/Component/Worker/Command/JsonCommandFormatTest.php @@ -0,0 +1,35 @@ + 'value']); + $expectedJson = json_encode( + [ + 'name' => 'name1', + 'parameters' => [ + 'param1' => 'value' + ] + ]); + + $this->assertEquals($expectedJson, JsonCommandFormat::newInstance()->marshal($command)); + } + + public function testUnmarshal() { + $command = JsonCommandFormat::newInstance()->unmarshal(json_encode( + [ + 'name' => 'name1', + 'parameters' => [ + 'param1' => 1 + ] + ] + )); + + $this->assertEquals('name1', $command->getName()); + $this->assertEquals(['param1' => 1], $command->getParameters()); + } +} From 93ff99f7c08940d2dd6c723254ef058b4ced1b08 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Wed, 5 Oct 2016 11:09:53 +0200 Subject: [PATCH 028/133] added toString method --- .../Component/Worker/Command/BasicCommand.php | 7 +++++++ .../Component/Worker/Command/BasicCommandTest.php | 12 ++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/SAREhub/Component/Worker/Command/BasicCommand.php b/src/SAREhub/Component/Worker/Command/BasicCommand.php index 08d65db..658157b 100644 --- a/src/SAREhub/Component/Worker/Command/BasicCommand.php +++ b/src/SAREhub/Component/Worker/Command/BasicCommand.php @@ -28,4 +28,11 @@ public function getName() { public function getParameters() { return $this->parameters; } + + public function __toString() { + return __CLASS__.':'.json_encode([ + 'name' => $this->getName(), + 'parameters' => $this->getParameters() + ]); + } } \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Command/BasicCommandTest.php b/tests/unit/SAREhub/Component/Worker/Command/BasicCommandTest.php index f61cb57..19b8faa 100644 --- a/tests/unit/SAREhub/Component/Worker/Command/BasicCommandTest.php +++ b/tests/unit/SAREhub/Component/Worker/Command/BasicCommandTest.php @@ -19,4 +19,16 @@ public function testCreateWithParameters() { $this->assertEquals('name', $command->getName()); $this->assertEquals($parameters, $command->getParameters()); } + + public function testToString() { + $command = new BasicCommand('name1', ['param1' => 1]); + + $expectedJson = json_encode([ + 'name' => 'name1', + 'parameters' => [ + 'param1' => 1 + ] + ]); + $this->assertEquals(BasicCommand::class.':'.$expectedJson, (string)$command); + } } From 55210e0110885b65d2e865e38a075ec2beac167c Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Thu, 6 Oct 2016 12:41:01 +0200 Subject: [PATCH 029/133] refactored worker interface and added Basic impl with as wrapper --- src/SAREhub/Component/Worker/BasicWorker.php | 118 ++++++++++++++++++ src/SAREhub/Component/Worker/Worker.php | 38 ++++-- .../Component/Worker/WorkerContext.php | 78 ++++++++++++ .../Component/Worker/BasicWorkerTest.php | 103 +++++++++++++++ 4 files changed, 328 insertions(+), 9 deletions(-) create mode 100644 src/SAREhub/Component/Worker/BasicWorker.php create mode 100644 src/SAREhub/Component/Worker/WorkerContext.php create mode 100644 tests/unit/SAREhub/Component/Worker/BasicWorkerTest.php diff --git a/src/SAREhub/Component/Worker/BasicWorker.php b/src/SAREhub/Component/Worker/BasicWorker.php new file mode 100644 index 0000000..5e18daa --- /dev/null +++ b/src/SAREhub/Component/Worker/BasicWorker.php @@ -0,0 +1,118 @@ +context = $context; + } + + public function start() { + if ($this->isStopped()) { + $this->doStart(); + $this->started = true; + } + } + + /** + * Contains custom worker start logic + * @throws WorkerException When something was wrong. + */ + protected abstract function doStart(); + + public function tick() { + if ($this->isStarted()) { + $this->doTick(); + } + } + + /** + * Contains custom worker tick logic + * @throws WorkerException When something was wrong. + */ + protected abstract function doTick(); + + public function stop() { + if ($this->isStarted()) { + $this->doStop(); + $this->started = false; + } + } + + /** + * Contains custom worker stop logic + * @throws WorkerException When something was wrong. + */ + protected abstract function doStop(); + + public function processCommand(Command $command) { + $this->doCommand($command); + } + + /** + * Contains custom worker command processing logic. + * + * @param Command $command + * @throws WorkerException When something was wrong. + */ + protected abstract function doCommand(Command $command); + + public function isStopped() { + return !$this->isStarted(); + } + + public function isStarted() { + return $this->started; + } + + public function getUuid() { + return $this->getContext()->getUuid(); + } + + public function getContext() { + return $this->context; + } + + /** + * Gets logger assigned to that object. + * @return LoggerInterface + */ + protected function getLogger() { + if ($this->logger) { + $this->logger = new NullLogger(); + } + + return $this->logger; + } + + public function setLogger(LoggerInterface $logger) { + $this->logger = $logger; + } + + +} \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Worker.php b/src/SAREhub/Component/Worker/Worker.php index 87efc1c..a397644 100644 --- a/src/SAREhub/Component/Worker/Worker.php +++ b/src/SAREhub/Component/Worker/Worker.php @@ -1,7 +1,8 @@ uuid = $uuid; + return $this; + } + + /** + * @return string + */ + public function getUuid() { + return $this->uuid; + } + + /** + * @param string $rootPath + * @return $this + */ + public function withRootPath($rootPath) { + $this->$rootPath = $rootPath; + return $this; + } + + /** + * @return string + */ + public function getRootPath() { + return $this->rootPath; + } + + /** + * @param array $arguments + * @return $this + */ + public function withArguments(array $arguments) { + $this->arguments = $arguments; + return $this; + } + + /** + * @return array + */ + public function getArguments() { + return $this->arguments; + } +} \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/BasicWorkerTest.php b/tests/unit/SAREhub/Component/Worker/BasicWorkerTest.php new file mode 100644 index 0000000..72e9f26 --- /dev/null +++ b/tests/unit/SAREhub/Component/Worker/BasicWorkerTest.php @@ -0,0 +1,103 @@ +createWorkerMethodSpy('doStart'); + $this->worker->start(); + $this->assertEquals(1, $this->methodSpy->getInvocationCount()); + + $this->assertTrue($this->worker->isStarted()); + $this->assertFalse($this->worker->isStopped()); + } + + public function testStartWhenStarted() { + $this->createWorkerMethodSpy('doStart'); + $this->worker->start(); + $this->worker->start(); + $this->assertEquals(1, $this->methodSpy->getInvocationCount()); + + $this->assertTrue($this->worker->isStarted()); + $this->assertFalse($this->worker->isStopped()); + } + + public function testStopWhenStarted() { + $this->createWorkerMethodSpy('doStop'); + $this->worker->start(); + $this->worker->stop(); + $this->assertEquals(1, $this->methodSpy->getInvocationCount()); + + $this->assertFalse($this->worker->isStarted()); + $this->assertTrue($this->worker->isStopped()); + } + + public function testStopWhenStopped() { + $this->createWorkerMethodSpy('doStop'); + $this->worker->stop(); + $this->assertFalse($this->methodSpy->hasBeenInvoked()); + + $this->assertFalse($this->worker->isStarted()); + $this->assertTrue($this->worker->isStopped()); + } + + public function testTickWhenStopped() { + $this->createWorkerMethodSpy('doTick'); + $this->worker->tick(); + $this->assertFalse($this->methodSpy->hasBeenInvoked()); + } + + public function testTickWhenStarted() { + $this->createWorkerMethodSpy('doTick'); + $this->worker->start(); + $this->worker->tick(); + $this->assertEquals(1, $this->methodSpy->getInvocationCount()); + } + + public function testProcessCommand() { + $this->createWorkerMethodSpy('doCommand'); + $command = new BasicCommand('test'); + $this->worker->processCommand($command); + $this->assertEquals(1, $this->methodSpy->getInvocationCount()); + $this->assertSame($command, $this->methodSpy->getInvocations()[0]->parameters[0]); + } + + private function createWorkerMethodSpy($method) { + $this->worker = $this->createPartialMock(TestWorker::class, [$method]); + $this->worker->expects($this->methodSpy = $this->any())->method($method); + } +} From 5e40483b0f45e84be175fc5c68b6b58b49e4a68e Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Thu, 6 Oct 2016 12:44:23 +0200 Subject: [PATCH 030/133] refactored WorkerRunner --- src/SAREhub/Component/Worker/WorkerRunner.php | 86 +++++-------------- .../Component/Worker/WorkerRunnerTest.php | 50 ++++++----- 2 files changed, 50 insertions(+), 86 deletions(-) diff --git a/src/SAREhub/Component/Worker/WorkerRunner.php b/src/SAREhub/Component/Worker/WorkerRunner.php index f4582ee..d7a298f 100644 --- a/src/SAREhub/Component/Worker/WorkerRunner.php +++ b/src/SAREhub/Component/Worker/WorkerRunner.php @@ -3,96 +3,54 @@ namespace SAREhub\Component\Worker; use SAREhub\Component\Worker\Command\CommandInput; -use SAREhub\Component\Worker\Command\Standard\StopWorkerCommand; -use SAREhub\Component\Worker\Command\StandardWorkerCommands; /** * Helper class for run worker. */ class WorkerRunner { - /** @var Worker */ - protected $worker; - - /** @var CommandInput */ - protected $commandInput; - - /** @var bool */ - protected $running = false; - - public function __construct(Worker $worker) { - $this->worker = $worker; - } - /** - * @param Worker $worker - * @return WorkerRunner - */ - public static function wrap(Worker $worker) { - return new self($worker); - } + * @var Worker + * */ + private $worker; /** - * @param CommandInput $commandInput - * @return $this + * @var CommandInput */ - public function commandInput(CommandInput $commandInput) { + private $commandInput; + + protected function __construct(Worker $worker, CommandInput $commandInput) { + $this->worker = $worker; $this->commandInput = $commandInput; - return $this; } - /** - * Starts worker loop. - */ - public function run() { - $this->start(); - while ($this->isRunning()) { - $this->tick(); - } + public static function newWithWorkerAndCommandInput(Worker $worker, CommandInput $commandInput) { + return new self($worker, $commandInput); } - /** - * Calls once on worker start. - */ public function start() { - if (!$this->isRunning()) { - $this->worker->onStart(); - $this->running = true; - } + $this->getWorker()->start(); } - /** - * Calls per main loop tick. - */ public function tick() { $this->checkCommand(); - if ($this->isRunning()) { - $this->worker->onTick(); - } - } - - protected function checkCommand() { - if ($command = $this->commandInput->getNextCommand()) { - if ($command instanceof StopWorkerCommand) { - $this->stop(); - $this->commandInput->sendCommandReply('1'); - } + if ($this->getWorker()->isStarted()) { + $this->getWorker()->tick(); + return true; } + + return false; } - /** - * Stop worker process - */ public function stop() { - $this->worker->onStop(); - $this->running = false; + $this->getWorker()->stop(); } - /** - * @return bool - */ - public function isRunning() { - return $this->running; + protected function checkCommand() { + if ($command = $this->getCommandInput()->getNextCommand()) { + $reply = $this->getWorker()->processCommand($command); + $this->getCommandInput()->sendCommandReply($reply); + } } /** diff --git a/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php b/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php index b7da8a0..b51a63e 100644 --- a/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php +++ b/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php @@ -1,12 +1,9 @@ workerMock = $this->createMock(Worker::class); + $this->workerMock = $this->createMock(SAREhub\Component\Worker\Worker::class); $this->commandInputMock = $this->createMock(CommandInput::class); - $this->workerRunner = WorkerRunner::wrap($this->workerMock)->commandInput($this->commandInputMock); + $this->workerRunner = WorkerRunner::newWithWorkerAndCommandInput($this->workerMock, $this->commandInputMock); } public function testStart() { - $this->workerMock->expects($this->once())->method('onStart'); - $this->workerRunner->start(); + $this->workerMock->expects($this->once())->method('start'); $this->workerRunner->start(); - $this->assertTrue($this->workerRunner->isRunning()); } public function testTick() { - $this->workerMock->expects($this->once())->method('onTick'); - $this->workerRunner->start(); - $this->commandInputMock->expects($this->once())->method('getNextCommand')->willReturn(null); + $this->workerMock->method('isStarted')->willReturn('true'); + $this->workerMock->expects($this->once())->method('tick'); $this->workerRunner->tick(); } public function testStop() { - $this->workerMock->expects($this->once())->method('onStop'); - $this->workerRunner->start(); + $this->workerMock->expects($this->once())->method('stop'); $this->workerRunner->stop(); - $this->assertFalse($this->workerRunner->isRunning()); } - public function testProcessStopCommand() { - $this->workerMock->expects($this->once())->method('onStop'); - $stopWorkerCommand = $this->getMockBuilder(StopWorkerCommand::class)->disableOriginalConstructor()->getMock(); - $this->commandInputMock->expects($this->once())->method('getNextCommand')->willReturn($stopWorkerCommand); + public function testCheckCommandWhenCommandWasReceive() { + $commmand = new BasicCommand('test'); + $commandReply = 'reply'; + $this->commandInputMock->expects($this->once())->method('getNextCommand')->willReturn($commmand); + $this->commandInputMock->expects($this->once())->method('sendCommandReply')->with($commandReply); + $this->workerMock->expects($this->once())->method('processCommand') + ->with($this->identicalTo($commmand))->willReturn($commandReply); - $this->workerRunner->start(); $this->workerRunner->tick(); - $this->assertFalse($this->workerRunner->isRunning()); } + public function testCheckCommandWhenNoCommand() { + $this->commandInputMock->expects($this->once())->method('getNextCommand')->willReturn(null); + $this->workerMock->expects($this->never())->method('processCommand'); + $this->workerRunner->tick(); + } + + public function testCheckCommandWhenWorkerIsStopped() { + $this->commandInputMock->expects($this->once())->method('getNextCommand')->willReturn(new BasicCommand('name')); + $this->commandInputMock->expects($this->once())->method('sendCommandReply'); + $this->workerMock->expects($this->once())->method('processCommand'); + + $this->workerRunner->tick(); + } } From 6189dc3df447678bb918ea74c27768d479389c17 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Thu, 6 Oct 2016 15:32:06 +0200 Subject: [PATCH 031/133] refactored --- .../Worker/Command/ZmqCommandInput.php | 64 +++++++------- .../Worker/Command/ZmqCommandOutput.php | 35 ++------ .../Worker/Command/ZmqCommandInputTest.php | 83 +++++++++---------- .../Worker/Command/ZmqCommandOutputTest.php | 66 ++++++--------- 4 files changed, 105 insertions(+), 143 deletions(-) diff --git a/src/SAREhub/Component/Worker/Command/ZmqCommandInput.php b/src/SAREhub/Component/Worker/Command/ZmqCommandInput.php index 0e75a4f..cdd9f1e 100644 --- a/src/SAREhub/Component/Worker/Command/ZmqCommandInput.php +++ b/src/SAREhub/Component/Worker/Command/ZmqCommandInput.php @@ -6,31 +6,37 @@ /** * Worker command input based on ZMQ Request/Reply method + * It will be create in non blocking mode */ class ZmqCommandInput implements CommandInput { - /** @var RequestReceiver */ - protected $commandReceiver; + /** + * @var RequestReceiver + */ + protected $receiver; - /** @var bool */ + /** + * @var bool + */ protected $blockingMode = false; - /** @var callable */ - protected $deserializer; - - protected function __construct(RequestReceiver $commandReceiver) { - $this->commandReceiver = $commandReceiver; - } + /** + * @var CommandFormat + */ + private $format; /** - * @param RequestReceiver $commandReceiver - * @return ZmqCommandInput + * @var Command */ - public static function forReceiver(RequestReceiver $commandReceiver) { - return new self($commandReceiver); + private $lastCommand = null; + + public function __construct(RequestReceiver $receiver, CommandFormat $format) { + $this->receiver = $receiver; + $this->format = $format; } /** + * Sets blocking mode for getNextCommand - will waits for next command * @return $this */ public function blockingMode() { @@ -46,32 +52,24 @@ public function nonBlockingMode() { return $this; } - /** - * @param callable $deserializer - * @return $this - */ - public function deserializer(callable $deserializer) { - $this->deserializer = $deserializer; - return $this; - } - public function getNextCommand() { - if ($commandData = $this->commandReceiver->receiveRequest($this->isInBlockingMode())) { - $deserializer = $this->deserializer; - $command = $deserializer($commandData); - if ($command instanceof Command) { - return $command; - } - - throw new CommandException("Deserializer must return Command instance: ".$command); + if ($this->lastCommand) { + throw new CommandException( + "Can't get next command, when reply for last wasn't sent, last command was: ".$this->lastCommand + ); } - return null; + $commandData = $this->receiver->receiveRequest($this->isInBlockingMode()); + $this->lastCommand = ($commandData) ? $this->format->unmarshal($commandData) : null; + return $this->lastCommand; } public function sendCommandReply($reply) { - $this->commandReceiver->sendReply($reply, $this->isInBlockingMode()); - return $this; + if ($this->lastCommand === null) { + throw new CommandException("Reply can be sent only when receive command"); + } + $this->receiver->sendReply($reply, $this->isInBlockingMode()); + $this->lastCommand = null; } /** diff --git a/src/SAREhub/Component/Worker/Command/ZmqCommandOutput.php b/src/SAREhub/Component/Worker/Command/ZmqCommandOutput.php index c489c89..67913ec 100644 --- a/src/SAREhub/Component/Worker/Command/ZmqCommandOutput.php +++ b/src/SAREhub/Component/Worker/Command/ZmqCommandOutput.php @@ -7,20 +7,13 @@ class ZmqCommandOutput implements CommandOutput { - protected $commandSender; - protected $blockingMode = false; - protected $serializer; + private $sender; + private $blockingMode = false; + private $format; - protected function __construct(RequestSender $commandSender) { - $this->commandSender = $commandSender; - } - - /** - * @param RequestSender $commandSender - * @return ZmqCommandOutput - */ - public static function forSender(RequestSender $commandSender) { - return new self($commandSender); + public function __construct(RequestSender $sender, CommandFormat $format) { + $this->sender = $sender; + $this->format = $format; } /** @@ -39,23 +32,13 @@ public function nonBlockingMode() { return $this; } - /** - * @param callable $serializer - * @return $this - */ - public function serializer(callable $serializer) { - $this->serializer = $serializer; - return $this; - } - public function sendCommand(Command $command) { - $serializer = $this->serializer; - $this->commandSender->sendRequest($serializer($command), $this->isInBlockingMode()); - return $this; + $commandData = $this->format->marshal($command); + $this->sender->sendRequest($commandData, $this->isInBlockingMode()); } public function getCommandReply() { - return $this->commandSender->receiveReply($this->isInBlockingMode()); + return $this->sender->receiveReply($this->isInBlockingMode()); } public function isInBlockingMode() { diff --git a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandInputTest.php b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandInputTest.php index 371f016..b738fe8 100644 --- a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandInputTest.php +++ b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandInputTest.php @@ -8,70 +8,67 @@ class ZmqCommandInputTest extends TestCase { - /** @var PHPUnit_Framework_MockObject_MockObject */ + /** + * @var PHPUnit_Framework_MockObject_MockObject + */ private $receiverMock; - /** @var PHPUnit_Framework_MockObject_MockObject */ - private $deserializerMock; + /** + * @var PHPUnit_Framework_MockObject_MockObject + */ + private $commandFormatMock; - /** @var PHPUnit_Framework_MockObject_MockObject */ - private $commandMock; - - /** @var ZmqCommandInput */ + /** + * @var ZmqCommandInput + */ private $commandInput; + private $commandData = 'command_data'; + protected function setUp() { $this->receiverMock = $this->createMock(RequestReceiver::class); - $this->deserializerMock = $this->getMockBuilder(\stdClass::class)->setMethods(['__invoke'])->getMock(); - $this->commandMock = $this->createMock(Command::class); - $this->deserializerMock->method('__invoke')->willReturn($this->commandMock); - - $this->commandInput = ZmqCommandInput::forReceiver($this->receiverMock) - ->deserializer($this->deserializerMock); + $this->commandFormatMock = $this->createMock(CommandFormat::class); + $this->commandInput = new ZmqCommandInput($this->receiverMock, $this->commandFormatMock); } - public function testGetNextCommand() { - $this->receiverMock->expects($this->once()) - ->method('receiveRequest') - ->with(false) - ->willReturn("command"); - $this->deserializerMock->expects($this->once()) - ->method('__invoke') - ->with('command') - ->willReturn($this->commandMock); - $this->assertSame($this->commandMock, $this->commandInput->getNextCommand()); + public function testGetNextCommandWhenNonBlockingMode() { + $command = new BasicCommand('name'); + $this->receiverMock->method('receiveRequest') + ->with(false)->willReturn($this->commandData); + $this->commandFormatMock->expects($this->once())->method('unmarshal') + ->with($this->commandData)->willReturn($command); + $this->assertSame($command, $this->commandInput->getNextCommand()); } - public function testGetNextCommandBlocking() { - $this->receiverMock->expects($this->once()) - ->method('receiveRequest') - ->with(true) - ->willReturn("command"); - $this->deserializerMock->expects($this->once()) - ->method('__invoke') - ->with('command') - ->willReturn($this->commandMock); - $this->assertSame($this->commandMock, $this->commandInput->blockingMode()->getNextCommand()); + public function testGetNextCommandWhenBlockingMode() { + $command = new BasicCommand('name'); + $this->receiverMock->method('receiveRequest')->with(true)->willReturn($this->commandData); + $this->commandFormatMock->expects($this->once())->method('unmarshal') + ->with($this->commandData)->willReturn($command); + $this->assertSame($command, $this->commandInput->blockingMode()->getNextCommand()); } public function testGetNextCommandWhenNotSent() { - $this->receiverMock->expects($this->once())->method('receiveRequest')->with(false)->willReturn(false); + $this->receiverMock->expects($this->once())->method('receiveRequest')->willReturn(false); + $this->commandFormatMock->expects($this->never())->method('unmarshal'); $this->assertNull($this->commandInput->getNextCommand()); } - public function testSendReply() { - $this->receiverMock->expects($this->once()) - ->method('sendReply') - ->with('reply', false) - ->willReturn($this->receiverMock); + public function testSendReplyWhenCommandWasReceive() { + $this->receiverMock->method('receiveRequest')->willReturn('c'); + $this->commandFormatMock->method('unmarshal')->willReturn(new BasicCommand('c')); + $this->commandInput->getNextCommand(); + + $this->receiverMock->expects($this->once())->method('sendReply')->with('reply', false); $this->commandInput->sendCommandReply('reply'); } public function testSendReplyBlocking() { - $this->receiverMock->expects($this->once()) - ->method('sendReply') - ->with('reply', true) - ->willReturn($this->receiverMock); + $this->receiverMock->method('receiveRequest')->willReturn('c'); + $this->commandFormatMock->method('unmarshal')->willReturn(new BasicCommand('c')); + $this->commandInput->getNextCommand(); + + $this->receiverMock->expects($this->once())->method('sendReply')->with('reply', true); $this->commandInput->blockingMode()->sendCommandReply('reply'); } } diff --git a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandOutputTest.php b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandOutputTest.php index 3a895d6..8a3fd32 100644 --- a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandOutputTest.php +++ b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandOutputTest.php @@ -12,64 +12,48 @@ class ZmqCommandOutputTest extends TestCase { private $senderMock; /** @var PHPUnit_Framework_MockObject_MockObject */ - private $serializerMock; - - /** @var PHPUnit_Framework_MockObject_MockObject */ - private $commandMock; + private $formatMock; /** @var ZmqCommandOutput */ private $commandOutput; protected function setUp() { $this->senderMock = $this->createMock(RequestSender::class); - $this->serializerMock = $this->getMockBuilder(\stdClass::class) - ->setMethods(['__invoke']) - ->getMock(); - $this->commandMock = $this->createMock(Command::class); - - - $this->commandOutput = ZmqCommandOutput::forSender($this->senderMock) - ->serializer($this->serializerMock); + $this->formatMock = $this->createMock(CommandFormat::class); + $this->commandOutput = new ZmqCommandOutput($this->senderMock, $this->formatMock); } - public function testSendCommand() { - $this->senderMock->expects($this->once()) - ->method('sendRequest') - ->with('command', false); + public function testSendCommandWhenNonBlockingMode() { + $command = new BasicCommand('c'); + $commandData = 'c'; + $this->senderMock->expects($this->once())->method('sendRequest') + ->with($commandData, false); + $this->formatMock->expects($this->once())->method('marshal') + ->with($this->identicalTo($command))->willReturn($commandData); - $this->serializerMock->expects($this->once()) - ->method('__invoke') - ->with($this->commandMock) - ->willReturn("command"); - $this->assertSame($this->commandOutput, $this->commandOutput->sendCommand($this->commandMock)); + $this->commandOutput->sendCommand($command); } - public function testSendBlocking() { - $this->senderMock->expects($this->once()) - ->method('sendRequest') - ->with('command', true); + public function testSendWhenBlockingMode() { + $command = new BasicCommand('c'); + $commandData = 'c'; + $this->senderMock->expects($this->once())->method('sendRequest') + ->with($commandData, true); + $this->formatMock->expects($this->once())->method('marshal') + ->with($this->identicalTo($command))->willReturn($commandData); - $this->serializerMock->expects($this->once()) - ->method('__invoke') - ->with($this->commandMock) - ->willReturn("command"); - $this->assertSame($this->commandOutput, $this->commandOutput->blockingMode() - ->sendCommand($this->commandMock)); + $this->commandOutput->blockingMode()->sendCommand($command); } - public function testGetCommandReply() { - $this->senderMock->expects($this->once()) - ->method('receiveReply') - ->with(false) - ->willReturn('reply'); + public function testGetCommandReplyWhenNonBlockingMode() { + $this->senderMock->expects($this->once())->method('receiveReply') + ->with(false)->willReturn('reply'); $this->assertEquals('reply', $this->commandOutput->getCommandReply()); } - public function testGetCommandReplyBlocking() { - $this->senderMock->expects($this->once()) - ->method('receiveReply') - ->with(true) - ->willReturn('reply'); + public function testGetCommandReplyWhenBlockingMode() { + $this->senderMock->expects($this->once())->method('receiveReply') + ->with(true)->willReturn('reply'); $this->assertEquals('reply', $this->commandOutput->blockingMode()->getCommandReply()); } } From c70bcb9bc2461c9c6f72853f31e7e7cac990ab8e Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Thu, 6 Oct 2016 15:32:27 +0200 Subject: [PATCH 032/133] deps update --- composer.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 06e7535..430df97 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,7 @@ { "name": "sarehub/component_worker", "description": "utility staff for create/manage worker processes", + "type": "library", "license": "MIT", "authors": [ { @@ -17,7 +18,8 @@ "require": { "php": "^5.6 || ^7.0", "symfony/process": "3.1.3 as 2.8.9", - "sarehub/commons": "0.*" + "sarehub/commons": "0.4.*", + "respect/validation": "1.1.*" }, "autoload": { "psr-4": { From 511f3fb2ddfcf50f80cf092cdac0fee8aba3985b Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Thu, 6 Oct 2016 16:09:07 +0200 Subject: [PATCH 033/133] refactored --- .../Worker/Manager/WorkerProcess.php | 52 ++++++++++++ .../Worker/Manager/WorkerProcessFactory.php | 74 ++++++++++++++++ .../Component/Worker/WorkerProcess.php | 82 ------------------ .../Component/Worker/WorkerProcessFactory.php | 85 ------------------- .../Manager/WorkerProcessFactoryTest.php | 46 ++++++++++ .../Worker/Manager/WorkerProcessTest.php | 41 +++++++++ .../Worker/WorkerProcessFactoryTest.php | 64 -------------- .../Component/Worker/WorkerProcessTest.php | 38 --------- 8 files changed, 213 insertions(+), 269 deletions(-) create mode 100644 src/SAREhub/Component/Worker/Manager/WorkerProcess.php create mode 100644 src/SAREhub/Component/Worker/Manager/WorkerProcessFactory.php delete mode 100644 src/SAREhub/Component/Worker/WorkerProcess.php delete mode 100644 src/SAREhub/Component/Worker/WorkerProcessFactory.php create mode 100644 tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessFactoryTest.php create mode 100644 tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessTest.php delete mode 100644 tests/unit/SAREhub/Component/Worker/WorkerProcessFactoryTest.php delete mode 100644 tests/unit/SAREhub/Component/Worker/WorkerProcessTest.php diff --git a/src/SAREhub/Component/Worker/Manager/WorkerProcess.php b/src/SAREhub/Component/Worker/Manager/WorkerProcess.php new file mode 100644 index 0000000..428c376 --- /dev/null +++ b/src/SAREhub/Component/Worker/Manager/WorkerProcess.php @@ -0,0 +1,52 @@ +uuid = $uuid; + $this->process = $process; + } + + + /** + * Starts worker process. + */ + public function start() { + $this->process->start(); + } + + /** + * Kills process via signal + */ + public function kill() { + $this->process->stop(); + } + + /** + * @return string + */ + public function getUuid() { + return $this->uuid; + } + + /** + * @return Process + */ + public function getProcess() { + return $this->process; + } +} \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Manager/WorkerProcessFactory.php b/src/SAREhub/Component/Worker/Manager/WorkerProcessFactory.php new file mode 100644 index 0000000..50a5757 --- /dev/null +++ b/src/SAREhub/Component/Worker/Manager/WorkerProcessFactory.php @@ -0,0 +1,74 @@ +runnerScriptPath = $path; + return $this; + } + + /** + * @param string $dir + * @return $this + */ + public function withWorkingDirectory($dir) { + $this->workingDirectory = $dir; + return $this; + } + + /** + * @param array $arguments + * @return $this + */ + public function withArguments(array $arguments) { + $this->arguments = $arguments; + return $this; + } + + /** + * @param string $workerUuid + * @return WorkerProcess + */ + public function create($workerUuid) { + v::notEmpty()->setName('runnerScriptPath')->check($this->runnerScriptPath); + + $standardArguments = ['php', $this->runnerScriptPath, $workerUuid]; + $processArguments = array_merge($standardArguments, $this->arguments); + $process = ProcessBuilder::create($processArguments) + ->setWorkingDirectory($this->workingDirectory) + ->getProcess(); + return new WorkerProcess($workerUuid, $process); + } +} \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/WorkerProcess.php b/src/SAREhub/Component/Worker/WorkerProcess.php deleted file mode 100644 index c40aa6c..0000000 --- a/src/SAREhub/Component/Worker/WorkerProcess.php +++ /dev/null @@ -1,82 +0,0 @@ -workerInfo = $workerInfo; - $this->process = $process; - } - - /** - * @param WorkerInfo $workerInfo - * @param Process $process - * @return WorkerProcess - */ - public static function getFor(WorkerInfo $workerInfo, Process $process) { - return new self($workerInfo, $process); - } - - /** - * @param CommandOutput $commandOutput - * @return $this - */ - public function commandOutput(CommandOutput $commandOutput) { - $this->commandOutput = $commandOutput; - return $this; - } - - - /** - * Starts worker process. - */ - public function start() { - $this->process->start(); - } - - /** - * Kills process via signal - */ - public function kill() { - $this->process->stop(); - } - - /** - * @return WorkerInfo - */ - public function getWorkerInfo() { - return $this->workerInfo; - } - - /** - * @return string - */ - public function getWorkerUuid() { - return $this->workerInfo->uuid; - } - - /** - * @return CommandOutput - */ - public function getCommandOutput() { - return $this->commandOutput; - } - - /** - * @return Process - */ - public function getProcess() { - return $this->process; - } -} \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/WorkerProcessFactory.php b/src/SAREhub/Component/Worker/WorkerProcessFactory.php deleted file mode 100644 index 314a287..0000000 --- a/src/SAREhub/Component/Worker/WorkerProcessFactory.php +++ /dev/null @@ -1,85 +0,0 @@ -runnerScript = $runnerScript; - return $factory->commandOutputFactory(self::getDefaultCommandOutputFactory()); - } - - /** - * Sets working directory for created worker processes. - * @param string $workingDirectory - * @return $this - */ - public function workingDirectory($workingDirectory) { - $this->workingDirectory = (string)$workingDirectory; - return $this; - } - - /** - * @param array $arguments - * @return $this - */ - public function arguments(array $arguments) { - $this->arguments = $arguments; - return $this; - } - - /** - * ```php - * function (Process $process) { - * return $commandOutput; - * } - * ``` - * @param callable $commandOutputFactory - * @return $this - */ - public function commandOutputFactory(callable $commandOutputFactory) { - $this->commandOutputFactory = $commandOutputFactory; - return $this; - } - - /** - * @return \Closure - */ - public static function getDefaultCommandOutputFactory() { - return function (Process $process) { - $process->setInput(new InputStream()); - return ProcessStreamCommandOutput::getForProcess($process); - }; - } - - /** - * @param WorkerInfo $workerInfo - * @return WorkerProcess - */ - public function create(WorkerInfo $workerInfo) { - $standardArguments = ['php', $this->runnerScript, $workerInfo->uuid]; - $processArguments = array_merge($standardArguments, $this->arguments); - $process = ProcessBuilder::create($processArguments) - ->setWorkingDirectory($this->workingDirectory) - ->getProcess(); - - $commandOutputFactory = $this->commandOutputFactory; - return WorkerProcess::getFor($workerInfo, $process) - ->commandOutput($commandOutputFactory($process)); - } -} \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessFactoryTest.php b/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessFactoryTest.php new file mode 100644 index 0000000..ca70121 --- /dev/null +++ b/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessFactoryTest.php @@ -0,0 +1,46 @@ +create('uuid'); + } + + public function testCreateWhenOnlyRunnerScriptPathSets() { + $factory = WorkerProcessFactory::newInstance()->withRunnerScriptPath('runner.php'); + $workerProcess = $factory->create('uuid'); + + $this->assertSame('uuid', $workerProcess->getUuid()); + $process = $workerProcess->getProcess(); + $this->assertInstanceOf(Process::class, $process); + $this->assertEquals('"php" "runner.php" "uuid"', $process->getCommandLine()); + } + + public function testCreateWithCustomWorkingDirectory() { + $factory = WorkerProcessFactory::newInstance() + ->withRunnerScriptPath('runner.php') + ->withWorkingDirectory('dir'); + + $workerProcess = $factory->create('uuid'); + $process = $workerProcess->getProcess(); + $this->assertEquals('dir', $process->getWorkingDirectory()); + } + + public function testCreateWithArguments() { + $factory = WorkerProcessFactory::newInstance() + ->withRunnerScriptPath('runner.php') + ->withArguments(['arg1', 'arg2']); + + $workerProcess = $factory->create('uuid'); + $process = $workerProcess->getProcess(); + $this->assertEquals('"php" "runner.php" "uuid" "arg1" "arg2"', $process->getCommandLine()); + } +} diff --git a/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessTest.php b/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessTest.php new file mode 100644 index 0000000..e7391d0 --- /dev/null +++ b/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessTest.php @@ -0,0 +1,41 @@ +processMock = $this->createMock(Process::class); + $this->workerProcess = new WorkerProcess($this->uuid, $this->processMock); + } + + public function testCreate() { + $this->assertEquals($this->uuid, $this->workerProcess->getUuid()); + $this->assertSame($this->processMock, $this->workerProcess->getProcess()); + } + + public function testStart() { + $this->processMock->expects($this->once())->method('start'); + $this->workerProcess->start(); + } + + + public function testKill() { + $this->processMock->expects($this->once())->method('stop'); + $this->workerProcess->kill(); + } +} diff --git a/tests/unit/SAREhub/Component/Worker/WorkerProcessFactoryTest.php b/tests/unit/SAREhub/Component/Worker/WorkerProcessFactoryTest.php deleted file mode 100644 index 9c680b4..0000000 --- a/tests/unit/SAREhub/Component/Worker/WorkerProcessFactoryTest.php +++ /dev/null @@ -1,64 +0,0 @@ -commandOutputFactoryMock = $this->getMockBuilder(\stdClass::class) - ->setMethods(['__invoke']) - ->getMock(); - - $this->commandOutputMock = $this->createMock(CommandOutput::class); - - $this->commandOutputFactoryMock->expects($this->once()) - ->method('__invoke') - ->with($this->isInstanceOf(Process::class)) - ->willReturn($this->commandOutputMock); - - - $this->factory = WorkerProcessFactory::getForRunnerScript('runner.php') - ->commandOutputFactory($this->commandOutputFactoryMock); - - $this->workerInfo = new WorkerInfo(); - $this->workerInfo->uuid = '123'; - } - - public function testCreate() { - $workerProcess = $this->factory->create($this->workerInfo); - $this->assertSame($this->workerInfo, $workerProcess->getWorkerInfo()); - $this->assertSame($this->commandOutputMock, $workerProcess->getCommandOutput()); - $process = $workerProcess->getProcess(); - $this->assertInstanceOf(Process::class, $process); - $this->assertEquals('"php" "runner.php" "123"', $process->getCommandLine()); - } - - public function testCreateWithCustomWorkingDirectory() { - $workerProcess = $this->factory->workingDirectory('testdir')->create($this->workerInfo); - $process = $workerProcess->getProcess(); - $this->assertEquals('testdir', $process->getWorkingDirectory()); - } - - public function testCreateWithArguments() { - $workerProcess = $this->factory->arguments(['arg1', 'arg2'])->create($this->workerInfo); - $process = $workerProcess->getProcess(); - $this->assertEquals('"php" "runner.php" "123" "arg1" "arg2"', $process->getCommandLine()); - } -} diff --git a/tests/unit/SAREhub/Component/Worker/WorkerProcessTest.php b/tests/unit/SAREhub/Component/Worker/WorkerProcessTest.php deleted file mode 100644 index 1c6979a..0000000 --- a/tests/unit/SAREhub/Component/Worker/WorkerProcessTest.php +++ /dev/null @@ -1,38 +0,0 @@ -processMock = $this->getMockBuilder(Process::class)->disableOriginalConstructor()->getMock(); - $this->commandOutputMock = $this->getMockBuilder(CommandOutput::class)->getMock(); - $this->workerProcess = WorkerProcess::getFor(new WorkerInfo(), $this->processMock) - ->commandOutput($this->commandOutputMock); - } - - public function testStart() { - $this->processMock->expects($this->once())->method('start'); - $this->workerProcess->start(); - } - - - public function testKill() { - $this->processMock->expects($this->once())->method('stop'); - $this->workerProcess->kill(); - } -} From ad12c4e09e46ba597ef4de8082f5251427b7868a Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Thu, 6 Oct 2016 16:09:45 +0200 Subject: [PATCH 034/133] refactored --- src/SAREhub/Component/Worker/Command/Command.php | 2 ++ src/SAREhub/Component/Worker/Command/CommandInput.php | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/SAREhub/Component/Worker/Command/Command.php b/src/SAREhub/Component/Worker/Command/Command.php index 247bfb9..a616098 100644 --- a/src/SAREhub/Component/Worker/Command/Command.php +++ b/src/SAREhub/Component/Worker/Command/Command.php @@ -16,4 +16,6 @@ public function getName(); * @return array */ public function getParameters(); + + public function __toString(); } \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Command/CommandInput.php b/src/SAREhub/Component/Worker/Command/CommandInput.php index 26f0463..5e23f17 100644 --- a/src/SAREhub/Component/Worker/Command/CommandInput.php +++ b/src/SAREhub/Component/Worker/Command/CommandInput.php @@ -16,7 +16,6 @@ public function getNextCommand(); /** * Sends reply for processed command * @param string $reply - * @return $this */ public function sendCommandReply($reply); } \ No newline at end of file From a595ad5ac138ac14d5214c611fad049cabb82bec Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Thu, 6 Oct 2016 16:10:12 +0200 Subject: [PATCH 035/133] fix --- .../Worker/Command/JsonCommandFormat.php | 3 -- .../Standard/KillAllWorkerManagerCommand.php | 15 ------ .../Command/Standard/KillWorkerCommand.php | 25 ---------- .../Command/Standard/StartWorkerCommand.php | 24 ---------- .../Command/Standard/StopAllWorkerCommand.php | 14 ------ .../Command/Standard/StopWorkerCommand.php | 23 --------- .../Worker/Command/WorkerCommand.php | 11 ----- src/SAREhub/Component/Worker/WorkerInfo.php | 48 ------------------- 8 files changed, 163 deletions(-) delete mode 100644 src/SAREhub/Component/Worker/Command/Standard/KillAllWorkerManagerCommand.php delete mode 100644 src/SAREhub/Component/Worker/Command/Standard/KillWorkerCommand.php delete mode 100644 src/SAREhub/Component/Worker/Command/Standard/StartWorkerCommand.php delete mode 100644 src/SAREhub/Component/Worker/Command/Standard/StopAllWorkerCommand.php delete mode 100644 src/SAREhub/Component/Worker/Command/Standard/StopWorkerCommand.php delete mode 100644 src/SAREhub/Component/Worker/Command/WorkerCommand.php delete mode 100644 src/SAREhub/Component/Worker/WorkerInfo.php diff --git a/src/SAREhub/Component/Worker/Command/JsonCommandFormat.php b/src/SAREhub/Component/Worker/Command/JsonCommandFormat.php index 4a51f8c..abe48d9 100644 --- a/src/SAREhub/Component/Worker/Command/JsonCommandFormat.php +++ b/src/SAREhub/Component/Worker/Command/JsonCommandFormat.php @@ -2,9 +2,6 @@ namespace SAREhub\Component\Worker\Command; - -use phpDocumentor\Command\Command; - class JsonCommandFormat implements CommandFormat { const NAME_INDEX = 'name'; diff --git a/src/SAREhub/Component/Worker/Command/Standard/KillAllWorkerManagerCommand.php b/src/SAREhub/Component/Worker/Command/Standard/KillAllWorkerManagerCommand.php deleted file mode 100644 index 38d60b3..0000000 --- a/src/SAREhub/Component/Worker/Command/Standard/KillAllWorkerManagerCommand.php +++ /dev/null @@ -1,15 +0,0 @@ -uuid = $uuid; - } - - public function getUuid() { - return $this->uuid; - } - - public function getName() { - return self::NAME; - } -} \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Command/Standard/StartWorkerCommand.php b/src/SAREhub/Component/Worker/Command/Standard/StartWorkerCommand.php deleted file mode 100644 index 3c1d20a..0000000 --- a/src/SAREhub/Component/Worker/Command/Standard/StartWorkerCommand.php +++ /dev/null @@ -1,24 +0,0 @@ -uuid = $uuid; - } - - public function getUuid() { - return $this->uuid; - } - - public function getName() { - return self::NAME; - } -} \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Command/Standard/StopAllWorkerCommand.php b/src/SAREhub/Component/Worker/Command/Standard/StopAllWorkerCommand.php deleted file mode 100644 index dcd35bb..0000000 --- a/src/SAREhub/Component/Worker/Command/Standard/StopAllWorkerCommand.php +++ /dev/null @@ -1,14 +0,0 @@ -uuid = $uuid; - } - - public function getUuid() { - return $this->uuid; - } - - public function getName() { - return self::NAME; - } -} \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Command/WorkerCommand.php b/src/SAREhub/Component/Worker/Command/WorkerCommand.php deleted file mode 100644 index bf0ff07..0000000 --- a/src/SAREhub/Component/Worker/Command/WorkerCommand.php +++ /dev/null @@ -1,11 +0,0 @@ -uuid = $uuid; - return $this; - } - - /** - * @param string $time - * @return $this - */ - public function startTime($time) { - $this->startTime = $time; - return $this; - } - - /** - * @return array - */ - public function toArray() { - return [ - 'uuid' => $this->uuid, - 'startTime' => $this->startTime - ]; - } -} \ No newline at end of file From 393cf82d488cdc1ed1aa62e98f65012d20a51210 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Fri, 7 Oct 2016 13:38:33 +0200 Subject: [PATCH 036/133] added CommandReply --- .../Worker/Command/CommandReplyTest.php | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 tests/unit/SAREhub/Component/Worker/Command/CommandReplyTest.php diff --git a/tests/unit/SAREhub/Component/Worker/Command/CommandReplyTest.php b/tests/unit/SAREhub/Component/Worker/Command/CommandReplyTest.php new file mode 100644 index 0000000..beabb01 --- /dev/null +++ b/tests/unit/SAREhub/Component/Worker/Command/CommandReplyTest.php @@ -0,0 +1,30 @@ +assertEquals('s', $reply->getStatus()); + $this->assertEquals('m', $reply->getMessage()); + $this->assertEquals('d', $reply->getData()); + } + + public function testSuccess() { + $reply = CommandReply::success('m', 'd'); + $this->assertEquals(CommandReply::SUCCESS_STATUS, $reply->getStatus()); + $this->assertEquals('m', $reply->getMessage()); + $this->assertEquals('d', $reply->getData()); + } + + public function testError() { + $reply = CommandReply::error('m', 'd'); + $this->assertEquals(CommandReply::ERROR_STATUS, $reply->getStatus()); + $this->assertEquals('m', $reply->getMessage()); + $this->assertEquals('d', $reply->getData()); + } + +} From 2973e8729494c0fade5e1498ed13c78121431413 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Fri, 7 Oct 2016 13:39:11 +0200 Subject: [PATCH 037/133] refactored --- .../Worker/Command/StandardCommandEnum.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/SAREhub/Component/Worker/Command/StandardCommandEnum.php diff --git a/src/SAREhub/Component/Worker/Command/StandardCommandEnum.php b/src/SAREhub/Component/Worker/Command/StandardCommandEnum.php new file mode 100644 index 0000000..ef2eb4d --- /dev/null +++ b/src/SAREhub/Component/Worker/Command/StandardCommandEnum.php @@ -0,0 +1,16 @@ + Date: Fri, 7 Oct 2016 13:39:43 +0200 Subject: [PATCH 038/133] added CommandReply --- .../Component/Worker/Command/CommandReply.php | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 src/SAREhub/Component/Worker/Command/CommandReply.php diff --git a/src/SAREhub/Component/Worker/Command/CommandReply.php b/src/SAREhub/Component/Worker/Command/CommandReply.php new file mode 100644 index 0000000..236850c --- /dev/null +++ b/src/SAREhub/Component/Worker/Command/CommandReply.php @@ -0,0 +1,95 @@ +status = $status; + $this->message = $message; + $this->data = $data; + } + + /** + * @param array $reply + * @return CommandReply + */ + public static function createFromArray(array $reply) { + return new self($reply['status'], $reply['message'], $reply['data']); + } + + /** + * @param string $message + * @param mixed $data + * @return CommandReply + */ + public static function success($message, $data = null) { + return self::reply(self::SUCCESS_STATUS, $message, $data); + } + + /** + * @param string $message + * @param mixed $data + * @return CommandReply + */ + public static function error($message, $data = null) { + return self::reply(self::ERROR_STATUS, $message, $data); + } + + /** + * @param string $status + * @param string $message + * @param mixed $data + * @return CommandReply + */ + public static function reply($status, $message, $data = null) { + return new self($status, $message, $data); + } + + /** + * @return string + */ + public function getStatus() { + return $this->status; + } + + /** + * @return string + */ + public function getMessage() { + return $this->message; + } + + /** + * @return mixed + */ + public function getData() { + return $this->data; + } + + public function jsonSerialize() { + return [ + 'status' => $this->getStatus(), + 'message' => $this->getMessage(), + 'data' => $this->getData() + ]; + } +} \ No newline at end of file From 4f0710e087dc016537218fef68160e1427756448 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Fri, 7 Oct 2016 14:04:49 +0200 Subject: [PATCH 039/133] CommandReply added isSuccess and isError --- .../Component/Worker/Command/CommandReply.php | 14 ++++++++++++++ .../Component/Worker/Command/CommandReplyTest.php | 10 ++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/SAREhub/Component/Worker/Command/CommandReply.php b/src/SAREhub/Component/Worker/Command/CommandReply.php index 236850c..ff92fa5 100644 --- a/src/SAREhub/Component/Worker/Command/CommandReply.php +++ b/src/SAREhub/Component/Worker/Command/CommandReply.php @@ -71,6 +71,20 @@ public function getStatus() { return $this->status; } + /** + * @return bool + */ + public function isSuccess() { + return $this->getStatus() === self::SUCCESS_STATUS; + } + + /** + * @return bool + */ + public function isError() { + return $this->getStatus() === self::ERROR_STATUS; + } + /** * @return string */ diff --git a/tests/unit/SAREhub/Component/Worker/Command/CommandReplyTest.php b/tests/unit/SAREhub/Component/Worker/Command/CommandReplyTest.php index beabb01..11789bc 100644 --- a/tests/unit/SAREhub/Component/Worker/Command/CommandReplyTest.php +++ b/tests/unit/SAREhub/Component/Worker/Command/CommandReplyTest.php @@ -27,4 +27,14 @@ public function testError() { $this->assertEquals('d', $reply->getData()); } + public function testIsSuccess() { + $reply = CommandReply::success('m', 'd'); + $this->assertTrue($reply->isSuccess()); + } + + public function testIsError() { + $reply = CommandReply::error('m', 'd'); + $this->assertTrue($reply->isError()); + } + } From a33a36b6558aef45090b65794657b3bdc5adfbda Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Fri, 7 Oct 2016 14:44:08 +0200 Subject: [PATCH 040/133] added close method --- src/SAREhub/Component/Worker/Command/CommandInput.php | 5 +++++ src/SAREhub/Component/Worker/Command/CommandOutput.php | 5 +++++ src/SAREhub/Component/Worker/Command/ZmqCommandInput.php | 7 +++++++ src/SAREhub/Component/Worker/Command/ZmqCommandOutput.php | 7 +++++++ .../Component/Worker/Command/ZmqCommandInputTest.php | 5 +++++ .../Component/Worker/Command/ZmqCommandOutputTest.php | 5 +++++ 6 files changed, 34 insertions(+) diff --git a/src/SAREhub/Component/Worker/Command/CommandInput.php b/src/SAREhub/Component/Worker/Command/CommandInput.php index 5e23f17..be219bb 100644 --- a/src/SAREhub/Component/Worker/Command/CommandInput.php +++ b/src/SAREhub/Component/Worker/Command/CommandInput.php @@ -18,4 +18,9 @@ public function getNextCommand(); * @param string $reply */ public function sendCommandReply($reply); + + /** + * Will close command input + */ + public function close(); } \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Command/CommandOutput.php b/src/SAREhub/Component/Worker/Command/CommandOutput.php index 29cfd1e..17fc413 100644 --- a/src/SAREhub/Component/Worker/Command/CommandOutput.php +++ b/src/SAREhub/Component/Worker/Command/CommandOutput.php @@ -19,4 +19,9 @@ public function sendCommand(Command $command); * @return string|null */ public function getCommandReply(); + + /** + * Will close output of command + */ + public function close(); } \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Command/ZmqCommandInput.php b/src/SAREhub/Component/Worker/Command/ZmqCommandInput.php index cdd9f1e..7d2bb9f 100644 --- a/src/SAREhub/Component/Worker/Command/ZmqCommandInput.php +++ b/src/SAREhub/Component/Worker/Command/ZmqCommandInput.php @@ -78,4 +78,11 @@ public function sendCommandReply($reply) { public function isInBlockingMode() { return $this->blockingMode; } + + /** + * Will close command input + */ + public function close() { + $this->receiver->unbind(); + } } \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Command/ZmqCommandOutput.php b/src/SAREhub/Component/Worker/Command/ZmqCommandOutput.php index 67913ec..aa06e20 100644 --- a/src/SAREhub/Component/Worker/Command/ZmqCommandOutput.php +++ b/src/SAREhub/Component/Worker/Command/ZmqCommandOutput.php @@ -44,4 +44,11 @@ public function getCommandReply() { public function isInBlockingMode() { return $this->blockingMode; } + + /** + * Will close output of command + */ + public function close() { + $this->sender->disconnect(); + } } \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandInputTest.php b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandInputTest.php index b738fe8..35baa9c 100644 --- a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandInputTest.php +++ b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandInputTest.php @@ -71,4 +71,9 @@ public function testSendReplyBlocking() { $this->receiverMock->expects($this->once())->method('sendReply')->with('reply', true); $this->commandInput->blockingMode()->sendCommandReply('reply'); } + + public function testClose() { + $this->receiverMock->expects($this->once())->method('unbind'); + $this->commandInput->close(); + } } diff --git a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandOutputTest.php b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandOutputTest.php index 8a3fd32..ed12d3e 100644 --- a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandOutputTest.php +++ b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandOutputTest.php @@ -56,4 +56,9 @@ public function testGetCommandReplyWhenBlockingMode() { ->with(true)->willReturn('reply'); $this->assertEquals('reply', $this->commandOutput->blockingMode()->getCommandReply()); } + + public function testClose() { + $this->senderMock->expects($this->once())->method('disconnect'); + $this->commandOutput->close(); + } } From ef0065443eea0c2eaf9db2d27ab630d3c9380c0f Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Fri, 7 Oct 2016 15:28:41 +0200 Subject: [PATCH 041/133] added throw CommandException when socket errors --- .../Component/Worker/Command/CommandException.php | 1 - .../Component/Worker/Command/CommandOutput.php | 3 ++- .../Component/Worker/Command/ZmqCommandOutput.php | 13 +++++++++++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/SAREhub/Component/Worker/Command/CommandException.php b/src/SAREhub/Component/Worker/Command/CommandException.php index 8f688ca..07068be 100644 --- a/src/SAREhub/Component/Worker/Command/CommandException.php +++ b/src/SAREhub/Component/Worker/Command/CommandException.php @@ -2,7 +2,6 @@ namespace SAREhub\Component\Worker\Command; - class CommandException extends \Exception { } \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Command/CommandOutput.php b/src/SAREhub/Component/Worker/Command/CommandOutput.php index 17fc413..7432d4d 100644 --- a/src/SAREhub/Component/Worker/Command/CommandOutput.php +++ b/src/SAREhub/Component/Worker/Command/CommandOutput.php @@ -10,13 +10,14 @@ interface CommandOutput { /** * Sends command to output. * @param Command $command - * @return $this + * @throws CommandException */ public function sendCommand(Command $command); /** * Gets reply for sent command if available or return nulll. * @return string|null + * @throws CommandException */ public function getCommandReply(); diff --git a/src/SAREhub/Component/Worker/Command/ZmqCommandOutput.php b/src/SAREhub/Component/Worker/Command/ZmqCommandOutput.php index aa06e20..397a343 100644 --- a/src/SAREhub/Component/Worker/Command/ZmqCommandOutput.php +++ b/src/SAREhub/Component/Worker/Command/ZmqCommandOutput.php @@ -34,11 +34,20 @@ public function nonBlockingMode() { public function sendCommand(Command $command) { $commandData = $this->format->marshal($command); - $this->sender->sendRequest($commandData, $this->isInBlockingMode()); + try { + $this->sender->sendRequest($commandData, $this->isInBlockingMode()); + } catch (\ZMQException $e) { + throw new CommandException("send command: ".$command, 0, $e); + } } + public function getCommandReply() { - return $this->sender->receiveReply($this->isInBlockingMode()); + try { + return $this->sender->receiveReply($this->isInBlockingMode()); + } catch (\ZMQException $e) { + throw new CommandException("get command reply ", $e); + } } public function isInBlockingMode() { From 6f6ece85ae8f46c41749fea9f48be2eaf211748a Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Fri, 7 Oct 2016 15:38:59 +0200 Subject: [PATCH 042/133] added createFromJson method --- src/SAREhub/Component/Worker/Command/CommandReply.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/SAREhub/Component/Worker/Command/CommandReply.php b/src/SAREhub/Component/Worker/Command/CommandReply.php index ff92fa5..5fdf996 100644 --- a/src/SAREhub/Component/Worker/Command/CommandReply.php +++ b/src/SAREhub/Component/Worker/Command/CommandReply.php @@ -28,6 +28,14 @@ protected function __construct($status, $message, $data) { $this->data = $data; } + /** + * @param string $reply + * @return CommandReply + */ + public static function createFromJson($reply) { + return self::createFromArray(json_decode($reply, true)); + } + /** * @param array $reply * @return CommandReply From 7be63c8d660f3f66bbddcf37ddb9d09e81659b2f Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Fri, 7 Oct 2016 15:39:12 +0200 Subject: [PATCH 043/133] added CommandOutputFactory --- .../Worker/Command/CommandOutputFactory.php | 11 ++++++++ .../Command/ZmqCommandOutputFactory.php | 28 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 src/SAREhub/Component/Worker/Command/CommandOutputFactory.php create mode 100644 src/SAREhub/Component/Worker/Command/ZmqCommandOutputFactory.php diff --git a/src/SAREhub/Component/Worker/Command/CommandOutputFactory.php b/src/SAREhub/Component/Worker/Command/CommandOutputFactory.php new file mode 100644 index 0000000..69fe763 --- /dev/null +++ b/src/SAREhub/Component/Worker/Command/CommandOutputFactory.php @@ -0,0 +1,11 @@ +format = $format; + $this->zmqContext = $context; + $this->dsnFactory = $dsnFactory; + } + + public function create($workerUuid) { + $sender = RequestSender::inContext($this->zmqContext) + ->connect(($this->dsnFactory)($workerUuid)); + return new ZmqCommandOutput($sender, $this->format); + } +} \ No newline at end of file From 7f7ac8608ac939e54f5bea2484d7ed87e7ff7524 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Fri, 7 Oct 2016 16:00:30 +0200 Subject: [PATCH 044/133] added WorkerCommandService --- .../Worker/Manager/WorkerCommandService.php | 120 ++++++++++++++++++ .../Manager/WorkerCommandServiceTest.php | 110 ++++++++++++++++ 2 files changed, 230 insertions(+) create mode 100644 src/SAREhub/Component/Worker/Manager/WorkerCommandService.php create mode 100644 tests/unit/SAREhub/Component/Worker/Manager/WorkerCommandServiceTest.php diff --git a/src/SAREhub/Component/Worker/Manager/WorkerCommandService.php b/src/SAREhub/Component/Worker/Manager/WorkerCommandService.php new file mode 100644 index 0000000..c836ad3 --- /dev/null +++ b/src/SAREhub/Component/Worker/Manager/WorkerCommandService.php @@ -0,0 +1,120 @@ +outputFactory = $factory; + $this->logger = new NullLogger(); + } + + /** + * @param stirng $uuid + */ + public function register($uuid) { + if (!$this->has($uuid)) { + $this->outputList[$uuid] = $this->outputFactory->create($uuid); + } + } + + /** + * @param string $uuid + */ + public function unregister($uuid) { + if ($output = $this->get($uuid)) { + $output->close(); + unset($this->outputList[$uuid]); + } + } + + /** + * @param string $uuid + * @param Command $command + * @return CommandReply + */ + public function sendCommand($uuid, Command $command) { + if ($output = $this->get($uuid)) { + try { + $output->sendCommand($command); + $timeoutTime = TimeProvider::get()->now() + $this->getCommandReplyTimeout(); + while (true) { + if ($reply = $output->getCommandReply()) { + return CommandReply::createFromJson($reply); + } + + if (TimeProvider::get()->now() >= $timeoutTime) { + return CommandReply::error('reply timeout'); + } + } + } catch (\Exception $e) { + $this->logger->error($e); + return CommandReply::error($e->getMessage()); + } + } + + return CommandReply::error('worker not exists', $uuid); + } + + /** + * @param string $uuid + * @return null|CommandOutput + */ + protected function get($uuid) { + return $this->has($uuid) ? $this->outputList[$uuid] : null; + } + + /** + * @param string $uuid + * @return bool + */ + public function has($uuid) { + return isset($this->outputList[$uuid]); + } + + public function setLogger(LoggerInterface $logger) { + $this->logger = $logger; + } + + /** + * @param int $timeout + */ + public function setCommandReplyTimeout($timeout) { + $this->commandReplyTimeout = $timeout; + } + + /** + * @return int + */ + public function getCommandReplyTimeout() { + return $this->commandReplyTimeout; + } +} \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Manager/WorkerCommandServiceTest.php b/tests/unit/SAREhub/Component/Worker/Manager/WorkerCommandServiceTest.php new file mode 100644 index 0000000..cf012f6 --- /dev/null +++ b/tests/unit/SAREhub/Component/Worker/Manager/WorkerCommandServiceTest.php @@ -0,0 +1,110 @@ +factoryMock = $this->createMock(CommandOutputFactory::class); + $this->outputMock = $this->createMock(CommandOutput::class); + $this->factoryMock->method('create')->willReturn($this->outputMock); + $this->service = new WorkerCommandService($this->factoryMock); + } + + public function testRegisterWhenNotExists() { + $this->factoryMock->expects($this->once())->method('create') + ->with('id')->willReturn($this->outputMock); + $this->service->register('id'); + $this->assertTrue($this->service->has('id')); + } + + public function testRegisterWhenExists() { + $this->service->register('id'); + $this->factoryMock->expects($this->never())->method('create'); + $this->service->register('id'); + $this->assertTrue($this->service->has('id')); + } + + public function testUnregisterWhenExists() { + $this->service->register('id'); + $this->outputMock->expects($this->once())->method('close'); + $this->service->unregister('id'); + $this->assertFalse($this->service->has('id')); + } + + public function testHasWhenNotExists() { + $this->assertFalse($this->service->has('not_exists')); + } + + public function testSendCommandWhenExists() { + $this->service->register('id'); + $command = new BasicCommand('c'); + $this->outputMock->expects($this->once())->method('sendCommand') + ->with($this->identicalTo($command)); + $this->outputMock->expects($this->once())->method('getCommandReply') + ->willReturn(json_encode(CommandReply::success('m'))); + + $reply = $this->service->sendCommand('id', $command); + $this->assertEquals('m', $reply->getMessage()); + } + + public function testSendCommandWhenNotExists() { + $command = new BasicCommand('c'); + $this->outputMock->expects($this->never())->method('sendCommand'); + $this->outputMock->expects($this->never())->method('getCommandReply'); + $reply = $this->service->sendCommand('id', $command); + $this->assertEquals('worker not exists', $reply->getMessage()); + } + + public function testSendCommandWhenReplyTimeout() { + $this->service->register('id'); + $command = new BasicCommand('c'); + $this->outputMock->expects($this->once())->method('getCommandReply'); + TimeProvider::get()->freezeTime(); + $this->service->setCommandReplyTimeout(0); + $reply = $this->service->sendCommand('id', $command); + $this->assertEquals('reply timeout', $reply->getMessage()); + TimeProvider::get()->unfreezeTime(); + } + + public function testSendCommandWhenSendCommandException() { + $this->service->register('id'); + $command = new BasicCommand('c'); + $this->outputMock->method('sendCommand') + ->willThrowException(new CommandException('m')); + $reply = $this->service->sendCommand('id', $command); + $this->assertEquals('m', $reply->getMessage()); + } + + public function testSendCommandWhenGetCommandReplyException() { + $this->service->register('id'); + $command = new BasicCommand('c'); + $this->outputMock->method('sendCommand') + ->willThrowException(new CommandException('m')); + $reply = $this->service->sendCommand('id', $command); + $this->assertEquals('m', $reply->getMessage()); + } +} From 86e097f81bb5cc669f00a84e6d296a1046360222 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Fri, 7 Oct 2016 16:02:08 +0200 Subject: [PATCH 045/133] added isRunning method --- src/SAREhub/Component/Worker/Manager/WorkerProcess.php | 4 ++++ .../SAREhub/Component/Worker/Manager/WorkerProcessTest.php | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/src/SAREhub/Component/Worker/Manager/WorkerProcess.php b/src/SAREhub/Component/Worker/Manager/WorkerProcess.php index 428c376..4946770 100644 --- a/src/SAREhub/Component/Worker/Manager/WorkerProcess.php +++ b/src/SAREhub/Component/Worker/Manager/WorkerProcess.php @@ -36,6 +36,10 @@ public function kill() { $this->process->stop(); } + public function isRunning() { + return $this->process->isRunning(); + } + /** * @return string */ diff --git a/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessTest.php b/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessTest.php index e7391d0..8d00f37 100644 --- a/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessTest.php +++ b/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessTest.php @@ -38,4 +38,9 @@ public function testKill() { $this->processMock->expects($this->once())->method('stop'); $this->workerProcess->kill(); } + + public function testIsRunning() { + $this->processMock->expects($this->once())->method('isRunning')->willReturn(true); + $this->assertTrue($this->workerProcess->isRunning()); + } } From 9f28d3cb8071b41fe1f1a002e24a2f1a01140a6a Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Fri, 7 Oct 2016 16:02:35 +0200 Subject: [PATCH 046/133] added StandedManagerCommands enum --- .../Manager/StandardManagerCommands.php | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/SAREhub/Component/Worker/Manager/StandardManagerCommands.php diff --git a/src/SAREhub/Component/Worker/Manager/StandardManagerCommands.php b/src/SAREhub/Component/Worker/Manager/StandardManagerCommands.php new file mode 100644 index 0000000..0586fdf --- /dev/null +++ b/src/SAREhub/Component/Worker/Manager/StandardManagerCommands.php @@ -0,0 +1,24 @@ + Date: Fri, 7 Oct 2016 16:02:58 +0200 Subject: [PATCH 047/133] update docs --- src/SAREhub/Component/Worker/Worker.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SAREhub/Component/Worker/Worker.php b/src/SAREhub/Component/Worker/Worker.php index a397644..2130cb8 100644 --- a/src/SAREhub/Component/Worker/Worker.php +++ b/src/SAREhub/Component/Worker/Worker.php @@ -3,6 +3,7 @@ namespace SAREhub\Component\Worker; use SAREhub\Component\Worker\Command\Command; +use SAREhub\Component\Worker\Command\CommandReply; /** * Represents Worker instance. @@ -30,8 +31,7 @@ public function stop(); /** * Executed when command was received. * @param Command $command - * @return mixed command reply - * @throws WorkerException When something was wrong. + * @return CommandReply command reply */ public function processCommand(Command $command); From 40f79e97c2a333a68a85d07f9090991446e6579d Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Fri, 7 Oct 2016 16:03:47 +0200 Subject: [PATCH 048/133] docs fix --- src/SAREhub/Component/Worker/Manager/WorkerCommandService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SAREhub/Component/Worker/Manager/WorkerCommandService.php b/src/SAREhub/Component/Worker/Manager/WorkerCommandService.php index c836ad3..3f4b8b5 100644 --- a/src/SAREhub/Component/Worker/Manager/WorkerCommandService.php +++ b/src/SAREhub/Component/Worker/Manager/WorkerCommandService.php @@ -38,7 +38,7 @@ public function __construct(CommandOutputFactory $factory) { } /** - * @param stirng $uuid + * @param string $uuid */ public function register($uuid) { if (!$this->has($uuid)) { From 39d6dec8e1a2b1997ab06d1ee9a5b31cf4792661 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Fri, 7 Oct 2016 16:04:16 +0200 Subject: [PATCH 049/133] added WorkerProcessService --- .../Worker/Manager/WorkerProcessService.php | 81 +++++++++++++++++++ .../Manager/WorkerProcessServiceTest.php | 63 +++++++++++++++ 2 files changed, 144 insertions(+) create mode 100644 src/SAREhub/Component/Worker/Manager/WorkerProcessService.php create mode 100644 tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessServiceTest.php diff --git a/src/SAREhub/Component/Worker/Manager/WorkerProcessService.php b/src/SAREhub/Component/Worker/Manager/WorkerProcessService.php new file mode 100644 index 0000000..c567173 --- /dev/null +++ b/src/SAREhub/Component/Worker/Manager/WorkerProcessService.php @@ -0,0 +1,81 @@ +processFactory = $factory; + $this->logger = new NullLogger(); + } + + /** + * @param string $uuid + * @return WorkerProcess + */ + public function register($uuid) { + if (!$this->has($uuid)) { + $process = $this->processFactory->create($uuid); + $this->processList[$uuid] = $process; + return $process; + } + } + + /** + * @param string $uuid + */ + public function unregister($uuid) { + if ($this->has($uuid)) { + unset($this->processList['uuid']); + } + } + + public function start($uuid) { + if ($process = $this->get($uuid)) { + $process->start(); + } + } + + public function kill($uuid) { + if ($process = $this->get($uuid)) { + $process->kill(); + } + } + + /** + * @param string $uuid + * @return null|WorkerProcess + */ + protected function get($uuid) { + return $this->has($uuid) ? $this->processList[$uuid] : null; + } + + /** + * @param string $uuid + * @return bool + */ + public function has($uuid) { + return isset($this->processList[$uuid]); + } + + public function setLogger(LoggerInterface $logger) { + $this->logger = $logger; + } +} \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessServiceTest.php b/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessServiceTest.php new file mode 100644 index 0000000..a7a6b42 --- /dev/null +++ b/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessServiceTest.php @@ -0,0 +1,63 @@ +factoryMock = $this->createMock(WorkerProcessFactory::class); + $this->process = $this->createMock(WorkerProcess::class); + $this->factoryMock->method('create')->willReturn($this->process); + $this->service = new WorkerProcessService($this->factoryMock); + + } + + public function testRegister() { + $this->service->register('uuid'); + $this->assertTrue($this->service->has('uuid')); + } + + public function testRegisterWhenExists() { + $this->service->register('uuid'); + $this->factoryMock->expects($this->never())->method('create'); + $this->assertTrue($this->service->has('uuid')); + } + + public function testUnregisterWhenExists() { + $this->service->register('uuid'); + $this->service->unregister('uuid'); + $this->assertFalse($this->service->has('uuid')); + } + + public function testStartWhenExists() { + $this->service->register('uuid'); + $this->process->expects($this->once())->method('start'); + $this->service->start('uuid'); + } + + public function testKillWhenExists() { + $this->service->register('uuid'); + $this->process->expects($this->once())->method('kill'); + $this->service->kill('uuid'); + } + + public function testHasWhenNotExists() { + $this->assertFalse($this->service->has('not_exists')); + } +} From 9b03aace3c49e55aac16c476233a31a5e0a8bddb Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Mon, 10 Oct 2016 13:47:37 +0200 Subject: [PATCH 050/133] fixed tests --- src/SAREhub/Component/Worker/BasicWorker.php | 31 ++++++--- .../Component/Worker/BasicWorkerTest.php | 68 ++++++++++++++----- 2 files changed, 73 insertions(+), 26 deletions(-) diff --git a/src/SAREhub/Component/Worker/BasicWorker.php b/src/SAREhub/Component/Worker/BasicWorker.php index 5e18daa..3cfc3f4 100644 --- a/src/SAREhub/Component/Worker/BasicWorker.php +++ b/src/SAREhub/Component/Worker/BasicWorker.php @@ -6,6 +6,7 @@ use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; use SAREhub\Component\Worker\Command\Command; +use SAREhub\Component\Worker\Command\CommandReply; /** * Worker implementation with auto handle lifecycle and logging support. @@ -24,7 +25,7 @@ abstract class BasicWorker implements Worker, LoggerAwareInterface { private $context; /** - * @var bool + * @var boolean */ private $started = false; @@ -36,6 +37,7 @@ public function start() { if ($this->isStopped()) { $this->doStart(); $this->started = true; + $this->getLogger()->info('Worker was started'); } } @@ -46,7 +48,7 @@ public function start() { protected abstract function doStart(); public function tick() { - if ($this->isStarted()) { + if ($this->isRunning()) { $this->doTick(); } } @@ -61,7 +63,9 @@ public function stop() { if ($this->isStarted()) { $this->doStop(); $this->started = false; + $this->getLogger()->info('Worker was stopped'); } + } /** @@ -71,7 +75,14 @@ public function stop() { protected abstract function doStop(); public function processCommand(Command $command) { - $this->doCommand($command); + $this->getLogger()->info('execute command: '.$command); + switch ($command->getName()) { + case StandardWorkerCommands::STOP: + $this->stop(); + return CommandReply::success('stopped'); + default: + return $this->doCommand($command); + } } /** @@ -90,8 +101,12 @@ public function isStarted() { return $this->started; } - public function getUuid() { - return $this->getContext()->getUuid(); + public function isRunning() { + return $this->isStarted(); + } + + public function getId() { + return $this->getContext()->getId(); } public function getContext() { @@ -102,8 +117,8 @@ public function getContext() { * Gets logger assigned to that object. * @return LoggerInterface */ - protected function getLogger() { - if ($this->logger) { + public function getLogger() { + if ($this->logger === null) { $this->logger = new NullLogger(); } @@ -113,6 +128,4 @@ protected function getLogger() { public function setLogger(LoggerInterface $logger) { $this->logger = $logger; } - - } \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/BasicWorkerTest.php b/tests/unit/SAREhub/Component/Worker/BasicWorkerTest.php index 72e9f26..60e23cf 100644 --- a/tests/unit/SAREhub/Component/Worker/BasicWorkerTest.php +++ b/tests/unit/SAREhub/Component/Worker/BasicWorkerTest.php @@ -5,6 +5,9 @@ use SAREhub\Component\Worker\BasicWorker; use SAREhub\Component\Worker\Command\BasicCommand; use SAREhub\Component\Worker\Command\Command; +use SAREhub\Component\Worker\Command\CommandReply; +use SAREhub\Component\Worker\StandardWorkerCommands; +use SAREhub\Component\Worker\WorkerContext; class TestWorker extends BasicWorker { @@ -21,14 +24,13 @@ protected function doStop() { } protected function doCommand(Command $command) { - } } class BasicWorkerTest extends TestCase { /** - * @var Worker + * @var TestWorker */ private $worker; @@ -37,42 +39,50 @@ class BasicWorkerTest extends TestCase { */ private $methodSpy; - public function testStartWhenStopped() { + protected function setUp() { + parent::setUp(); + $this->worker = new TestWorker(WorkerContext::newInstance()); + } + + public function testStartWhenStoppedThenDoStart() { $this->createWorkerMethodSpy('doStart'); $this->worker->start(); $this->assertEquals(1, $this->methodSpy->getInvocationCount()); - + } + + public function testIsStartedWhenStoppedThenReturnFalse() { + $this->assertFalse($this->worker->isStarted()); + } + + public function testIsStartedWhenStartedThenReturnTrue() { + $this->worker->start(); $this->assertTrue($this->worker->isStarted()); - $this->assertFalse($this->worker->isStopped()); } - public function testStartWhenStarted() { + public function testStartWhenStartedThenNoop() { $this->createWorkerMethodSpy('doStart'); $this->worker->start(); $this->worker->start(); $this->assertEquals(1, $this->methodSpy->getInvocationCount()); - - $this->assertTrue($this->worker->isStarted()); - $this->assertFalse($this->worker->isStopped()); } - public function testStopWhenStarted() { + public function testStopWhenStartedThenDoStop() { $this->createWorkerMethodSpy('doStop'); $this->worker->start(); $this->worker->stop(); $this->assertEquals(1, $this->methodSpy->getInvocationCount()); - + } + + public function testStopWhenStartedThenIsStartedReturnFalse() { + $this->worker->start(); + $this->worker->stop(); $this->assertFalse($this->worker->isStarted()); - $this->assertTrue($this->worker->isStopped()); } public function testStopWhenStopped() { $this->createWorkerMethodSpy('doStop'); $this->worker->stop(); $this->assertFalse($this->methodSpy->hasBeenInvoked()); - - $this->assertFalse($this->worker->isStarted()); - $this->assertTrue($this->worker->isStopped()); } public function testTickWhenStopped() { @@ -88,7 +98,7 @@ public function testTickWhenStarted() { $this->assertEquals(1, $this->methodSpy->getInvocationCount()); } - public function testProcessCommand() { + public function testProcessCommandWhenCustomCommandThenDoCommand() { $this->createWorkerMethodSpy('doCommand'); $command = new BasicCommand('test'); $this->worker->processCommand($command); @@ -96,8 +106,32 @@ public function testProcessCommand() { $this->assertSame($command, $this->methodSpy->getInvocations()[0]->parameters[0]); } + public function testProcessCommandWhenCustomCommandThenReturnReply() { + $this->createWorkerSpy('doCommand'); + $expectedReply = CommandReply::success('r'); + $this->worker->expects($this->once())->method('doCommand')->willReturn($expectedReply); + $this->assertSame($expectedReply, $this->worker->processCommand(new BasicCommand('test'))); + } + + public function testProcessCommandWhenStopCommand() { + + $this->createWorkerMethodSpy('stop'); + $this->worker->processCommand(new BasicCommand(StandardWorkerCommands::STOP)); + $this->assertEquals(1, $this->methodSpy->getInvocationCount()); + } + + public function testProcessCommandWhenStopCommandThenReturnSuccessReply() { + $this->worker = new TestWorker(WorkerContext::newInstance()); + $reply = $this->worker->processCommand(new BasicCommand(StandardWorkerCommands::STOP)); + $this->assertTrue($reply->isSuccess()); + } + private function createWorkerMethodSpy($method) { - $this->worker = $this->createPartialMock(TestWorker::class, [$method]); + $this->createWorkerSpy($method); $this->worker->expects($this->methodSpy = $this->any())->method($method); } + + private function createWorkerSpy($method) { + $this->worker = $this->createPartialMock(TestWorker::class, [$method]); + } } From 86cf8d72c564d36b383f0d639a50e631645cbb94 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Mon, 10 Oct 2016 13:49:02 +0200 Subject: [PATCH 051/133] fixed tests --- src/SAREhub/Component/Worker/Manager/WorkerProcess.php | 10 +++++----- .../Component/Worker/Manager/WorkerProcessTest.php | 10 +--------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/SAREhub/Component/Worker/Manager/WorkerProcess.php b/src/SAREhub/Component/Worker/Manager/WorkerProcess.php index 4946770..569e4ff 100644 --- a/src/SAREhub/Component/Worker/Manager/WorkerProcess.php +++ b/src/SAREhub/Component/Worker/Manager/WorkerProcess.php @@ -12,12 +12,12 @@ class WorkerProcess { /** * @var string */ - private $uuid; + private $id; private $process; - public function __construct($uuid, Process $process) { - $this->uuid = $uuid; + public function __construct($id, Process $process) { + $this->id = $id; $this->process = $process; } @@ -43,8 +43,8 @@ public function isRunning() { /** * @return string */ - public function getUuid() { - return $this->uuid; + public function getId() { + return $this->id; } /** diff --git a/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessTest.php b/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessTest.php index 8d00f37..9411524 100644 --- a/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessTest.php +++ b/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessTest.php @@ -6,8 +6,6 @@ class WorkerProcessTest extends TestCase { - private $uuid = 'id'; - /** * @var PHPUnit_Framework_MockObject_MockObject */ @@ -20,12 +18,7 @@ class WorkerProcessTest extends TestCase { protected function setUp() { $this->processMock = $this->createMock(Process::class); - $this->workerProcess = new WorkerProcess($this->uuid, $this->processMock); - } - - public function testCreate() { - $this->assertEquals($this->uuid, $this->workerProcess->getUuid()); - $this->assertSame($this->processMock, $this->workerProcess->getProcess()); + $this->workerProcess = new WorkerProcess('id', $this->processMock); } public function testStart() { @@ -33,7 +26,6 @@ public function testStart() { $this->workerProcess->start(); } - public function testKill() { $this->processMock->expects($this->once())->method('stop'); $this->workerProcess->kill(); From 5506c7566a44d5f0d5b67b2afa12d361f3afee3d Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Mon, 10 Oct 2016 13:49:26 +0200 Subject: [PATCH 052/133] fixed for worker id --- .../Worker/Manager/WorkerProcessFactory.php | 8 ++++---- .../Worker/Manager/WorkerProcessFactoryTest.php | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/SAREhub/Component/Worker/Manager/WorkerProcessFactory.php b/src/SAREhub/Component/Worker/Manager/WorkerProcessFactory.php index 50a5757..65944d9 100644 --- a/src/SAREhub/Component/Worker/Manager/WorkerProcessFactory.php +++ b/src/SAREhub/Component/Worker/Manager/WorkerProcessFactory.php @@ -58,17 +58,17 @@ public function withArguments(array $arguments) { } /** - * @param string $workerUuid + * @param string $workerId * @return WorkerProcess */ - public function create($workerUuid) { + public function create($workerId) { v::notEmpty()->setName('runnerScriptPath')->check($this->runnerScriptPath); - $standardArguments = ['php', $this->runnerScriptPath, $workerUuid]; + $standardArguments = ['php', $this->runnerScriptPath, $workerId]; $processArguments = array_merge($standardArguments, $this->arguments); $process = ProcessBuilder::create($processArguments) ->setWorkingDirectory($this->workingDirectory) ->getProcess(); - return new WorkerProcess($workerUuid, $process); + return new WorkerProcess($workerId, $process); } } \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessFactoryTest.php b/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessFactoryTest.php index ca70121..3fa13df 100644 --- a/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessFactoryTest.php +++ b/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessFactoryTest.php @@ -11,17 +11,17 @@ class WorkerProcessFactoryTest extends TestCase { */ public function testCreateWhenRunnerScriptPathEmpty() { $factory = WorkerProcessFactory::newInstance(); - $factory->create('uuid'); + $factory->create('id'); } public function testCreateWhenOnlyRunnerScriptPathSets() { $factory = WorkerProcessFactory::newInstance()->withRunnerScriptPath('runner.php'); - $workerProcess = $factory->create('uuid'); + $workerProcess = $factory->create('id'); - $this->assertSame('uuid', $workerProcess->getUuid()); + $this->assertSame('id', $workerProcess->getId()); $process = $workerProcess->getProcess(); $this->assertInstanceOf(Process::class, $process); - $this->assertEquals('"php" "runner.php" "uuid"', $process->getCommandLine()); + $this->assertEquals('"php" "runner.php" "id"', $process->getCommandLine()); } public function testCreateWithCustomWorkingDirectory() { @@ -29,7 +29,7 @@ public function testCreateWithCustomWorkingDirectory() { ->withRunnerScriptPath('runner.php') ->withWorkingDirectory('dir'); - $workerProcess = $factory->create('uuid'); + $workerProcess = $factory->create('id'); $process = $workerProcess->getProcess(); $this->assertEquals('dir', $process->getWorkingDirectory()); } @@ -39,8 +39,8 @@ public function testCreateWithArguments() { ->withRunnerScriptPath('runner.php') ->withArguments(['arg1', 'arg2']); - $workerProcess = $factory->create('uuid'); + $workerProcess = $factory->create('id'); $process = $workerProcess->getProcess(); - $this->assertEquals('"php" "runner.php" "uuid" "arg1" "arg2"', $process->getCommandLine()); + $this->assertEquals('"php" "runner.php" "id" "arg1" "arg2"', $process->getCommandLine()); } } From 73c9cef8477d6bc25a961a78f8562b15ca7c8559 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Mon, 10 Oct 2016 13:51:02 +0200 Subject: [PATCH 053/133] changed interface --- src/SAREhub/Component/Worker/Worker.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/SAREhub/Component/Worker/Worker.php b/src/SAREhub/Component/Worker/Worker.php index 2130cb8..b1a2bd1 100644 --- a/src/SAREhub/Component/Worker/Worker.php +++ b/src/SAREhub/Component/Worker/Worker.php @@ -45,10 +45,12 @@ public function isStarted(); */ public function isStopped(); + public function isRunning(); + /** * @return string */ - public function getUuid(); + public function getId(); /** * @return WorkerContext From ff82adefb6f7bc582bb2988b7d8439b815c19500 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Mon, 10 Oct 2016 13:51:24 +0200 Subject: [PATCH 054/133] enum for worker command names --- .../Worker/Command/StandardCommandEnum.php | 16 ---------------- .../Component/Worker/StandardWorkerCommands.php | 8 ++++++++ 2 files changed, 8 insertions(+), 16 deletions(-) delete mode 100644 src/SAREhub/Component/Worker/Command/StandardCommandEnum.php create mode 100644 src/SAREhub/Component/Worker/StandardWorkerCommands.php diff --git a/src/SAREhub/Component/Worker/Command/StandardCommandEnum.php b/src/SAREhub/Component/Worker/Command/StandardCommandEnum.php deleted file mode 100644 index ef2eb4d..0000000 --- a/src/SAREhub/Component/Worker/Command/StandardCommandEnum.php +++ /dev/null @@ -1,16 +0,0 @@ - Date: Mon, 10 Oct 2016 13:58:11 +0200 Subject: [PATCH 055/133] fixed id --- src/SAREhub/Component/Worker/WorkerContext.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/SAREhub/Component/Worker/WorkerContext.php b/src/SAREhub/Component/Worker/WorkerContext.php index e17cad5..06e3074 100644 --- a/src/SAREhub/Component/Worker/WorkerContext.php +++ b/src/SAREhub/Component/Worker/WorkerContext.php @@ -10,7 +10,7 @@ class WorkerContext { /** * @var string */ - private $uuid; + private $id; /** * @var string @@ -29,19 +29,19 @@ public static function newInstance() { } /** - * @param string $uuid + * @param string $id * @return $this */ - public function withUuid($uuid) { - $this->uuid = $uuid; + public function withId($id) { + $this->id = $id; return $this; } /** * @return string */ - public function getUuid() { - return $this->uuid; + public function getId() { + return $this->id; } /** From 5c5f657557f4f4a832d2aa51b738ddfe8bfb0151 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Mon, 10 Oct 2016 14:03:06 +0200 Subject: [PATCH 056/133] remove unused deps --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 430df97..e023048 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,7 @@ "require": { "php": "^5.6 || ^7.0", "symfony/process": "3.1.3 as 2.8.9", - "sarehub/commons": "0.4.*", + "sarehub/commons": "0.5.*", "respect/validation": "1.1.*" }, "autoload": { From 87f794df5c57d377fd76910e629d3cfb24181026 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Mon, 10 Oct 2016 15:26:50 +0200 Subject: [PATCH 057/133] refactored --- .../Component/Worker/StandardWorkerCommands.php | 8 -------- src/SAREhub/Component/Worker/WorkerCommands.php | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 8 deletions(-) delete mode 100644 src/SAREhub/Component/Worker/StandardWorkerCommands.php create mode 100644 src/SAREhub/Component/Worker/WorkerCommands.php diff --git a/src/SAREhub/Component/Worker/StandardWorkerCommands.php b/src/SAREhub/Component/Worker/StandardWorkerCommands.php deleted file mode 100644 index 017fcf7..0000000 --- a/src/SAREhub/Component/Worker/StandardWorkerCommands.php +++ /dev/null @@ -1,8 +0,0 @@ - Date: Mon, 10 Oct 2016 15:27:15 +0200 Subject: [PATCH 058/133] removed stop tests --- .../Component/Worker/BasicWorkerTest.php | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/tests/unit/SAREhub/Component/Worker/BasicWorkerTest.php b/tests/unit/SAREhub/Component/Worker/BasicWorkerTest.php index 60e23cf..1920358 100644 --- a/tests/unit/SAREhub/Component/Worker/BasicWorkerTest.php +++ b/tests/unit/SAREhub/Component/Worker/BasicWorkerTest.php @@ -6,7 +6,6 @@ use SAREhub\Component\Worker\Command\BasicCommand; use SAREhub\Component\Worker\Command\Command; use SAREhub\Component\Worker\Command\CommandReply; -use SAREhub\Component\Worker\StandardWorkerCommands; use SAREhub\Component\Worker\WorkerContext; class TestWorker extends BasicWorker { @@ -98,7 +97,7 @@ public function testTickWhenStarted() { $this->assertEquals(1, $this->methodSpy->getInvocationCount()); } - public function testProcessCommandWhenCustomCommandThenDoCommand() { + public function testProcessCommandThenDoCommand() { $this->createWorkerMethodSpy('doCommand'); $command = new BasicCommand('test'); $this->worker->processCommand($command); @@ -106,26 +105,13 @@ public function testProcessCommandWhenCustomCommandThenDoCommand() { $this->assertSame($command, $this->methodSpy->getInvocations()[0]->parameters[0]); } - public function testProcessCommandWhenCustomCommandThenReturnReply() { + public function testProcessCommandThenReturnReply() { $this->createWorkerSpy('doCommand'); $expectedReply = CommandReply::success('r'); $this->worker->expects($this->once())->method('doCommand')->willReturn($expectedReply); $this->assertSame($expectedReply, $this->worker->processCommand(new BasicCommand('test'))); } - public function testProcessCommandWhenStopCommand() { - - $this->createWorkerMethodSpy('stop'); - $this->worker->processCommand(new BasicCommand(StandardWorkerCommands::STOP)); - $this->assertEquals(1, $this->methodSpy->getInvocationCount()); - } - - public function testProcessCommandWhenStopCommandThenReturnSuccessReply() { - $this->worker = new TestWorker(WorkerContext::newInstance()); - $reply = $this->worker->processCommand(new BasicCommand(StandardWorkerCommands::STOP)); - $this->assertTrue($reply->isSuccess()); - } - private function createWorkerMethodSpy($method) { $this->createWorkerSpy($method); $this->worker->expects($this->methodSpy = $this->any())->method($method); From 2774cab05bfb7055be31c28aa2d6cd330d79f026 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Mon, 10 Oct 2016 15:37:13 +0200 Subject: [PATCH 059/133] fixed --- .../Worker/Manager/WorkerProcessService.php | 50 +++++++++++-------- .../Manager/WorkerProcessServiceTest.php | 14 +++--- 2 files changed, 37 insertions(+), 27 deletions(-) diff --git a/src/SAREhub/Component/Worker/Manager/WorkerProcessService.php b/src/SAREhub/Component/Worker/Manager/WorkerProcessService.php index c567173..1674b4b 100644 --- a/src/SAREhub/Component/Worker/Manager/WorkerProcessService.php +++ b/src/SAREhub/Component/Worker/Manager/WorkerProcessService.php @@ -2,7 +2,6 @@ namespace SAREhub\Component\Worker\Manager; - use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; @@ -27,52 +26,63 @@ public function __construct(WorkerProcessFactory $factory) { } /** - * @param string $uuid + * @param string $id * @return WorkerProcess */ - public function register($uuid) { - if (!$this->has($uuid)) { - $process = $this->processFactory->create($uuid); - $this->processList[$uuid] = $process; + public function register($id) { + if (!$this->has($id)) { + $process = $this->processFactory->create($id); + $this->processList[$id] = $process; + $this->getLogger()->info('registered worker process: '.$id); return $process; } } /** - * @param string $uuid + * @param string $id */ - public function unregister($uuid) { - if ($this->has($uuid)) { - unset($this->processList['uuid']); + public function unregister($id) { + if ($this->has($id)) { + unset($this->processList[$id]); + $this->getLogger()->info('unregistered worker process: '.$id); } } - public function start($uuid) { - if ($process = $this->get($uuid)) { + public function start($id) { + if ($process = $this->get($id)) { $process->start(); + $this->getLogger()->info('started worker process: '.$id); } } - public function kill($uuid) { - if ($process = $this->get($uuid)) { + public function kill($id) { + if ($process = $this->get($id)) { $process->kill(); + $this->getLogger()->info('killed worker process: '.$id); } } /** - * @param string $uuid + * @param string $id * @return null|WorkerProcess */ - protected function get($uuid) { - return $this->has($uuid) ? $this->processList[$uuid] : null; + protected function get($id) { + return $this->has($id) ? $this->processList[$id] : null; } /** - * @param string $uuid + * @param string $id * @return bool */ - public function has($uuid) { - return isset($this->processList[$uuid]); + public function has($id) { + return isset($this->processList[$id]); + } + + /** + * @return LoggerInterface + */ + public function getLogger() { + return $this->logger; } public function setLogger(LoggerInterface $logger) { diff --git a/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessServiceTest.php b/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessServiceTest.php index a7a6b42..d4d3c63 100644 --- a/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessServiceTest.php +++ b/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessServiceTest.php @@ -40,21 +40,21 @@ public function testRegisterWhenExists() { } public function testUnregisterWhenExists() { - $this->service->register('uuid'); - $this->service->unregister('uuid'); - $this->assertFalse($this->service->has('uuid')); + $this->service->register('worker'); + $this->service->unregister('worker'); + $this->assertFalse($this->service->has('worker')); } public function testStartWhenExists() { - $this->service->register('uuid'); + $this->service->register('id'); $this->process->expects($this->once())->method('start'); - $this->service->start('uuid'); + $this->service->start('id'); } public function testKillWhenExists() { - $this->service->register('uuid'); + $this->service->register('id'); $this->process->expects($this->once())->method('kill'); - $this->service->kill('uuid'); + $this->service->kill('id'); } public function testHasWhenNotExists() { From de0b286b3bc160c227f6050fb9c2443452308ebd Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Tue, 11 Oct 2016 10:20:27 +0200 Subject: [PATCH 060/133] extracted logic of start,stop from worker to Service --- .../Component/Worker/Service/Service.php | 39 ++++++ .../Worker/Service/ServiceSupport.php | 107 ++++++++++++++++ .../Worker/Service/ServiceSupportTest.php | 118 ++++++++++++++++++ 3 files changed, 264 insertions(+) create mode 100644 src/SAREhub/Component/Worker/Service/Service.php create mode 100644 src/SAREhub/Component/Worker/Service/ServiceSupport.php create mode 100644 tests/unit/SAREhub/Component/Worker/Service/ServiceSupportTest.php diff --git a/src/SAREhub/Component/Worker/Service/Service.php b/src/SAREhub/Component/Worker/Service/Service.php new file mode 100644 index 0000000..2465180 --- /dev/null +++ b/src/SAREhub/Component/Worker/Service/Service.php @@ -0,0 +1,39 @@ +isStarted()) { + $this->doStart(); + $this->started = true; + $this->stopped = false; + } + } + + /** + * Contains custom worker start logic + * @throws \Exception When something was wrong. + */ + protected abstract function doStart(); + + /** + * Executed on every service tick. + * @throws \Exception When something was wrong. + */ + public function tick() { + if ($this->isRunning()) { + $this->doTick(); + } + } + + /** + * Contains custom worker tick logic + * @throws \Exception When something was wrong. + */ + protected abstract function doTick(); + + /** + * Executed for stop service + * @throws \Exception When something was wrong. + */ + public function stop() { + if ($this->isStarted()) { + $this->doStop(); + $this->started = false; + $this->stopped = true; + } + } + + /** + * Contains custom worker stop logic + * @throws \Exception When something was wrong. + */ + protected abstract function doStop(); + + /** + * @return boolean + */ + public function isStarted() { + return $this->started; + } + + /** + * @return boolean + */ + public function isStopped() { + return $this->stopped; + } + + /** + * @return boolean + */ + public function isRunning() { + return $this->started; + } + + /** + * Gets logger assigned to that object. + * @return LoggerInterface + */ + protected function getLogger() { + if ($this->logger === null) { + $this->logger = new NullLogger(); + } + + return $this->logger; + } + + public function setLogger(LoggerInterface $logger) { + $this->logger = $logger; + } +} \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Service/ServiceSupportTest.php b/tests/unit/SAREhub/Component/Worker/Service/ServiceSupportTest.php new file mode 100644 index 0000000..6e2146a --- /dev/null +++ b/tests/unit/SAREhub/Component/Worker/Service/ServiceSupportTest.php @@ -0,0 +1,118 @@ +service = $this->createPartialMock(TestServiceSupport::class, $spyMethods); + } + + public function testIsStartedWhenCreatedThenReturnFalse() { + $this->assertFalse($this->service->isStarted()); + } + + public function testIsRunningWhenCreatedThenReturnFalse() { + $this->assertFalse($this->service->isRunning()); + } + + public function testStartWhenStoppedThenIsStartedReturnTrue() { + $this->service->start(); + $this->assertTrue($this->service->isStarted()); + } + + public function testStartWhenStoppedThenCallDoStart() { + $spy = $this->getMethodSpy('doStart'); + $this->service->start(); + $this->assertEquals(1, $spy->getInvocationCount()); + } + + public function testStartWhenStartedThenNotCallDoStart() { + $this->service->start(); + $spy = $this->getMethodSpy('doStart'); + $this->service->start(); + $this->assertFalse($spy->hasBeenInvoked()); + } + + public function testIsStoppedWhenCreatedThenReturnTrue() { + $this->assertTrue($this->service->isStopped()); + } + + public function testIsStoppedWhenStartedThenReturnFalse() { + $this->service->start(); + $this->assertFalse($this->service->isStopped()); + } + + public function testStopWhenStartedThenIsStoppedReturnTrue() { + $this->service->start(); + $this->service->stop(); + $this->assertTrue($this->service->isStopped()); + } + + public function testStopThenIsStartedReturnFalse() { + $this->service->stop(); + $this->assertFalse($this->service->isStarted()); + } + + public function testStopThenIsRunningReturnFalse() { + $this->service->stop(); + $this->assertFalse($this->service->isRunning()); + } + + public function testStopWhenStartedThenCallDoStop() { + $this->service->start(); + $spy = $this->getMethodSpy('doStop'); + $this->service->stop(); + $this->assertEquals(1, $spy->getInvocationCount()); + } + + public function testStopWhenStoppedThenNotCallDoStop() { + $spy = $this->getMethodSpy('doStop'); + $this->service->stop(); + $this->assertFalse($spy->hasBeenInvoked()); + } + + public function testTickWhenRunningThenDoTick() { + $this->service->start(); + $spy = $this->getMethodSpy('doTick'); + $this->service->tick(); + $this->assertEquals(1, $spy->getInvocationCount()); + } + + public function testTickWhenNotRunningThenNotDoTick() { + $spy = $this->getMethodSpy('doTick'); + $this->service->tick(); + $this->assertFalse($spy->hasBeenInvoked()); + } + + private function getMethodSpy($method) { + $this->service->expects($methodSpy = $this->any())->method($method); + return $methodSpy; + } +} From 49cee560dc56e3cbdf9c3a1ca892fdcd875e92bb Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Tue, 11 Oct 2016 10:21:33 +0200 Subject: [PATCH 061/133] implements Service logic --- src/SAREhub/Component/Worker/BasicWorker.php | 96 +------------------ src/SAREhub/Component/Worker/Worker.php | 33 +------ .../Component/Worker/BasicWorkerTest.php | 87 +++-------------- 3 files changed, 20 insertions(+), 196 deletions(-) diff --git a/src/SAREhub/Component/Worker/BasicWorker.php b/src/SAREhub/Component/Worker/BasicWorker.php index 3cfc3f4..b7b1e04 100644 --- a/src/SAREhub/Component/Worker/BasicWorker.php +++ b/src/SAREhub/Component/Worker/BasicWorker.php @@ -2,109 +2,37 @@ namespace SAREhub\Component\Worker; -use Psr\Log\LoggerAwareInterface; -use Psr\Log\LoggerInterface; -use Psr\Log\NullLogger; use SAREhub\Component\Worker\Command\Command; -use SAREhub\Component\Worker\Command\CommandReply; +use SAREhub\Component\Worker\Service\ServiceSupport; /** * Worker implementation with auto handle lifecycle and logging support. * Use that class for create concrete worker with logic. */ -abstract class BasicWorker implements Worker, LoggerAwareInterface { - - /** - * @var LoggerInterface - */ - private $logger; +abstract class BasicWorker extends ServiceSupport implements Worker { /** * @var WorkerContext */ private $context; - /** - * @var boolean - */ - private $started = false; - public function __construct(WorkerContext $context) { $this->context = $context; } - public function start() { - if ($this->isStopped()) { - $this->doStart(); - $this->started = true; - $this->getLogger()->info('Worker was started'); - } - } - - /** - * Contains custom worker start logic - * @throws WorkerException When something was wrong. - */ - protected abstract function doStart(); - - public function tick() { - if ($this->isRunning()) { - $this->doTick(); - } - } - - /** - * Contains custom worker tick logic - * @throws WorkerException When something was wrong. - */ - protected abstract function doTick(); - - public function stop() { - if ($this->isStarted()) { - $this->doStop(); - $this->started = false; - $this->getLogger()->info('Worker was stopped'); - } - - } - - /** - * Contains custom worker stop logic - * @throws WorkerException When something was wrong. - */ - protected abstract function doStop(); - public function processCommand(Command $command) { $this->getLogger()->info('execute command: '.$command); - switch ($command->getName()) { - case StandardWorkerCommands::STOP: - $this->stop(); - return CommandReply::success('stopped'); - default: - return $this->doCommand($command); - } + return $this->doCommand($command); } /** - * Contains custom worker command processing logic. + * Contains custom command processing logic. * * @param Command $command * @throws WorkerException When something was wrong. */ protected abstract function doCommand(Command $command); - public function isStopped() { - return !$this->isStarted(); - } - - public function isStarted() { - return $this->started; - } - - public function isRunning() { - return $this->isStarted(); - } - public function getId() { return $this->getContext()->getId(); } @@ -112,20 +40,4 @@ public function getId() { public function getContext() { return $this->context; } - - /** - * Gets logger assigned to that object. - * @return LoggerInterface - */ - public function getLogger() { - if ($this->logger === null) { - $this->logger = new NullLogger(); - } - - return $this->logger; - } - - public function setLogger(LoggerInterface $logger) { - $this->logger = $logger; - } } \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Worker.php b/src/SAREhub/Component/Worker/Worker.php index b1a2bd1..c8d0329 100644 --- a/src/SAREhub/Component/Worker/Worker.php +++ b/src/SAREhub/Component/Worker/Worker.php @@ -4,29 +4,12 @@ use SAREhub\Component\Worker\Command\Command; use SAREhub\Component\Worker\Command\CommandReply; +use SAREhub\Component\Worker\Service\Service; /** * Represents Worker instance. */ -interface Worker { - - /** - * Executed for start worker - * @throws WorkerException When something was wrong. - */ - public function start(); - - /** - * Executed on every tick, must implements worker logic code. - * @throws WorkerException When something was wrong. - */ - public function tick(); - - /** - * Executed for stop worker - * @throws WorkerException When something was wrong. - */ - public function stop(); +interface Worker extends Service { /** * Executed when command was received. @@ -35,18 +18,6 @@ public function stop(); */ public function processCommand(Command $command); - /** - * @return boolean - */ - public function isStarted(); - - /** - * @return boolean - */ - public function isStopped(); - - public function isRunning(); - /** * @return string */ diff --git a/tests/unit/SAREhub/Component/Worker/BasicWorkerTest.php b/tests/unit/SAREhub/Component/Worker/BasicWorkerTest.php index 1920358..081c5e1 100644 --- a/tests/unit/SAREhub/Component/Worker/BasicWorkerTest.php +++ b/tests/unit/SAREhub/Component/Worker/BasicWorkerTest.php @@ -6,9 +6,8 @@ use SAREhub\Component\Worker\Command\BasicCommand; use SAREhub\Component\Worker\Command\Command; use SAREhub\Component\Worker\Command\CommandReply; -use SAREhub\Component\Worker\WorkerContext; -class TestWorker extends BasicWorker { +class TestBasicWorker extends BasicWorker { protected function doStart() { @@ -23,101 +22,43 @@ protected function doStop() { } protected function doCommand(Command $command) { + } } class BasicWorkerTest extends TestCase { /** - * @var TestWorker + * @var TestBasicWorker */ private $worker; - /** - * @var PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount - */ - private $methodSpy; - protected function setUp() { parent::setUp(); - $this->worker = new TestWorker(WorkerContext::newInstance()); - } - - public function testStartWhenStoppedThenDoStart() { - $this->createWorkerMethodSpy('doStart'); - $this->worker->start(); - $this->assertEquals(1, $this->methodSpy->getInvocationCount()); - } - - public function testIsStartedWhenStoppedThenReturnFalse() { - $this->assertFalse($this->worker->isStarted()); - } - - public function testIsStartedWhenStartedThenReturnTrue() { - $this->worker->start(); - $this->assertTrue($this->worker->isStarted()); - } - - public function testStartWhenStartedThenNoop() { - $this->createWorkerMethodSpy('doStart'); - $this->worker->start(); - $this->worker->start(); - $this->assertEquals(1, $this->methodSpy->getInvocationCount()); + $this->worker = $this->createPartialMock(TestBasicWorker::class, ['doCommand']); } - public function testStopWhenStartedThenDoStop() { - $this->createWorkerMethodSpy('doStop'); - $this->worker->start(); - $this->worker->stop(); - $this->assertEquals(1, $this->methodSpy->getInvocationCount()); - } - - public function testStopWhenStartedThenIsStartedReturnFalse() { - $this->worker->start(); - $this->worker->stop(); - $this->assertFalse($this->worker->isStarted()); - } - - public function testStopWhenStopped() { - $this->createWorkerMethodSpy('doStop'); - $this->worker->stop(); - $this->assertFalse($this->methodSpy->hasBeenInvoked()); - } - - public function testTickWhenStopped() { - $this->createWorkerMethodSpy('doTick'); - $this->worker->tick(); - $this->assertFalse($this->methodSpy->hasBeenInvoked()); - } - - public function testTickWhenStarted() { - $this->createWorkerMethodSpy('doTick'); - $this->worker->start(); - $this->worker->tick(); - $this->assertEquals(1, $this->methodSpy->getInvocationCount()); + public function testProcessCommandThenDoCommand() { + $spy = $this->getMethodSpy('doCommand'); + $this->worker->processCommand(new BasicCommand('test')); + $this->assertEquals(1, $spy->getInvocationCount()); } - public function testProcessCommandThenDoCommand() { - $this->createWorkerMethodSpy('doCommand'); + public function testProcessCommandThenDoCommandWithCommandParameter() { + $spy = $this->getMethodSpy('doCommand'); $command = new BasicCommand('test'); $this->worker->processCommand($command); - $this->assertEquals(1, $this->methodSpy->getInvocationCount()); - $this->assertSame($command, $this->methodSpy->getInvocations()[0]->parameters[0]); + $this->assertSame($command, $spy->getInvocations()[0]->parameters[0]); } public function testProcessCommandThenReturnReply() { - $this->createWorkerSpy('doCommand'); $expectedReply = CommandReply::success('r'); $this->worker->expects($this->once())->method('doCommand')->willReturn($expectedReply); $this->assertSame($expectedReply, $this->worker->processCommand(new BasicCommand('test'))); } - private function createWorkerMethodSpy($method) { - $this->createWorkerSpy($method); - $this->worker->expects($this->methodSpy = $this->any())->method($method); - } - - private function createWorkerSpy($method) { - $this->worker = $this->createPartialMock(TestWorker::class, [$method]); + private function getMethodSpy($method) { + $this->worker->expects($methodSpy = $this->any())->method($method); + return $methodSpy; } } From fe876523e57a44e770ae6aac2e035dc8728f57bd Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Tue, 11 Oct 2016 10:21:52 +0200 Subject: [PATCH 062/133] name fix --- src/SAREhub/Component/Worker/Command/CommandOutputFactory.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SAREhub/Component/Worker/Command/CommandOutputFactory.php b/src/SAREhub/Component/Worker/Command/CommandOutputFactory.php index 69fe763..cd917e2 100644 --- a/src/SAREhub/Component/Worker/Command/CommandOutputFactory.php +++ b/src/SAREhub/Component/Worker/Command/CommandOutputFactory.php @@ -4,8 +4,8 @@ interface CommandOutputFactory { /** - * @param string $workerUuid + * @param string $workerId * @return CommandOutput */ - public function create($workerUuid); + public function create($workerId); } \ No newline at end of file From a004ba1236632eb3ac20fec5e77e2a36a5927d27 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Tue, 11 Oct 2016 10:22:14 +0200 Subject: [PATCH 063/133] fix --- tests/unit/SAREhub/Component/Worker/Command/BasicCommandTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/unit/SAREhub/Component/Worker/Command/BasicCommandTest.php b/tests/unit/SAREhub/Component/Worker/Command/BasicCommandTest.php index 19b8faa..4eeff0d 100644 --- a/tests/unit/SAREhub/Component/Worker/Command/BasicCommandTest.php +++ b/tests/unit/SAREhub/Component/Worker/Command/BasicCommandTest.php @@ -6,7 +6,6 @@ class BasicCommandTest extends TestCase { - public function testCreateWithoutParameters() { $command = new BasicCommand('name'); $this->assertEquals('name', $command->getName()); From 29b1da8400f1b05fbd77bc106035d698bb1bb81d Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Tue, 11 Oct 2016 11:01:32 +0200 Subject: [PATCH 064/133] fixes --- ...anagerCommands.php => ManagerCommands.php} | 16 +- .../Worker/Manager/WorkerCommandService.php | 74 +++---- .../Worker/Manager/WorkerManager.php | 109 +++++++++ .../Component/Worker/WorkerManager.php | 208 ------------------ .../Manager/WorkerCommandServiceTest.php | 3 +- .../Worker/Manager/WorkerManagerTest.php | 106 +++++++++ .../Component/Worker/WorkerManagerTest.php | 66 ------ 7 files changed, 268 insertions(+), 314 deletions(-) rename src/SAREhub/Component/Worker/Manager/{StandardManagerCommands.php => ManagerCommands.php} (64%) create mode 100644 src/SAREhub/Component/Worker/Manager/WorkerManager.php delete mode 100644 src/SAREhub/Component/Worker/WorkerManager.php create mode 100644 tests/unit/SAREhub/Component/Worker/Manager/WorkerManagerTest.php delete mode 100644 tests/unit/SAREhub/Component/Worker/WorkerManagerTest.php diff --git a/src/SAREhub/Component/Worker/Manager/StandardManagerCommands.php b/src/SAREhub/Component/Worker/Manager/ManagerCommands.php similarity index 64% rename from src/SAREhub/Component/Worker/Manager/StandardManagerCommands.php rename to src/SAREhub/Component/Worker/Manager/ManagerCommands.php index 0586fdf..1a9b97c 100644 --- a/src/SAREhub/Component/Worker/Manager/StandardManagerCommands.php +++ b/src/SAREhub/Component/Worker/Manager/ManagerCommands.php @@ -3,7 +3,9 @@ namespace SAREhub\Component\Worker\Manager; -class StandardManagerCommands { +use SAREhub\Component\Worker\Command\BasicCommand; + +class ManagerCommands { const COMMAND_NAME_PREFIX = 'worker.manager.'; @@ -21,4 +23,16 @@ class StandardManagerCommands { const STATUS = self::COMMAND_NAME_PREFIX.'status'; const INFO = self::COMMAND_NAME_PREFIX.'info'; const STATS = self::COMMAND_NAME_PREFIX.'stats'; + + /** + * @param $workerId + * @return BasicCommand + */ + public static function start($workerId) { + return new BasicCommand(self::START, ['id' => $workerId]); + } + + public static function stop($workerId) { + return new BasicCommand(self::STOP, ['id' => $workerId]); + } } \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Manager/WorkerCommandService.php b/src/SAREhub/Component/Worker/Manager/WorkerCommandService.php index 3f4b8b5..442924b 100644 --- a/src/SAREhub/Component/Worker/Manager/WorkerCommandService.php +++ b/src/SAREhub/Component/Worker/Manager/WorkerCommandService.php @@ -2,7 +2,6 @@ namespace SAREhub\Component\Worker\Manager; -use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; use SAREhub\Commons\Misc\TimeProvider; @@ -10,8 +9,9 @@ use SAREhub\Component\Worker\Command\CommandOutput; use SAREhub\Component\Worker\Command\CommandOutputFactory; use SAREhub\Component\Worker\Command\CommandReply; +use SAREhub\Component\Worker\Service\ServiceSupport; -class WorkerCommandService implements LoggerAwareInterface { +class WorkerCommandService extends ServiceSupport { const DEFAULT_COMMAND_REPLY_TIMEOUT = 30; @@ -30,42 +30,41 @@ class WorkerCommandService implements LoggerAwareInterface { */ private $outputList = []; - private $commandReplyTimeout = self::DEFAULT_COMMAND_REPLY_TIMEOUT; - public function __construct(CommandOutputFactory $factory) { $this->outputFactory = $factory; $this->logger = new NullLogger(); } /** - * @param string $uuid + * @param string $id */ - public function register($uuid) { - if (!$this->has($uuid)) { - $this->outputList[$uuid] = $this->outputFactory->create($uuid); + public function register($id) { + if (!$this->has($id)) { + $this->outputList[$id] = $this->outputFactory->create($id); } } /** - * @param string $uuid + * @param string $id */ - public function unregister($uuid) { - if ($output = $this->get($uuid)) { + public function unregister($id) { + if ($output = $this->get($id)) { $output->close(); - unset($this->outputList[$uuid]); + unset($this->outputList[$id]); } } /** - * @param string $uuid + * @param string $id * @param Command $command + * @param int $replyTimeout * @return CommandReply */ - public function sendCommand($uuid, Command $command) { - if ($output = $this->get($uuid)) { + public function sendCommand($id, Command $command, $replyTimeout = self::DEFAULT_COMMAND_REPLY_TIMEOUT) { + if ($output = $this->get($id)) { try { $output->sendCommand($command); - $timeoutTime = TimeProvider::get()->now() + $this->getCommandReplyTimeout(); + $timeoutTime = TimeProvider::get()->now() + $replyTimeout; while (true) { if ($reply = $output->getCommandReply()) { return CommandReply::createFromJson($reply); @@ -81,40 +80,41 @@ public function sendCommand($uuid, Command $command) { } } - return CommandReply::error('worker not exists', $uuid); + return CommandReply::error('worker not exists', $id); } - /** - * @param string $uuid - * @return null|CommandOutput - */ - protected function get($uuid) { - return $this->has($uuid) ? $this->outputList[$uuid] : null; + protected function doStart() { + } - /** - * @param string $uuid - * @return bool - */ - public function has($uuid) { - return isset($this->outputList[$uuid]); + protected function doTick() { + } - public function setLogger(LoggerInterface $logger) { - $this->logger = $logger; + protected function doStop() { + foreach ($this->outputList as $id => $output) { + $this->unregister($id); + } } + /** - * @param int $timeout + * @param string $id + * @return null|CommandOutput */ - public function setCommandReplyTimeout($timeout) { - $this->commandReplyTimeout = $timeout; + protected function get($id) { + return $this->has($id) ? $this->outputList[$id] : null; } /** - * @return int + * @param string $id + * @return bool */ - public function getCommandReplyTimeout() { - return $this->commandReplyTimeout; + public function has($id) { + return isset($this->outputList[$id]); + } + + public function setLogger(LoggerInterface $logger) { + $this->logger = $logger; } } \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Manager/WorkerManager.php b/src/SAREhub/Component/Worker/Manager/WorkerManager.php new file mode 100644 index 0000000..73719ea --- /dev/null +++ b/src/SAREhub/Component/Worker/Manager/WorkerManager.php @@ -0,0 +1,109 @@ +commandService = $service; + return $this; + } + + public function withProcessService(WorkerProcessService $service) { + $this->processService = $service; + return $this; + } + + protected function doStart() { + + } + + protected function doTick() { + + } + + protected function doStop() { + $this->commandService->stop(); + } + + protected function doCommand(Command $command) { + switch ($command->getName()) { + case ManagerCommands::START: + return $this->onStartCommand($command); + case ManagerCommands::STOP: + return $this->onStopCommand($command); + } + + $this->getLogger()->warning('Unknown command ', ['command' => $command]); + return CommandReply::error('unknown command', $command->getName()); + } + + protected function onStartCommand(Command $command) { + $id = $command->getParameters()['id']; + $context = ['command' => $command]; + + if ($this->getProcessService()->has($id)) { + $message = 'worker with same id running'; + $this->getLogger()->warning($message, $context); + return CommandReply::error($message); + } + + $this->getProcessService()->register($id); + $this->getProcessService()->start($id); + $this->getCommandService()->register($id); + + $message = 'worker started'; + $this->getLogger()->info($message, $context); + return CommandReply::success($message); + } + + protected function onStopCommand(Command $command) { + $id = $command->getParameters()['id']; + $this->getLogger()->info('send stop command to worker', ['command' => $command]); + + $reply = $this->getCommandService()->sendCommand($id, WorkerCommands::stop()); + if ($reply->isSuccess()) { + $this->getProcessService()->unregister($id); + $this->getCommandService()->unregister($id); + } + return $reply; + } + + /** + * @return WorkerProcessService + */ + protected function getProcessService() { + return $this->processService; + } + + /** + * @return WorkerCommandService + */ + protected function getCommandService() { + return $this->commandService; + } +} \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/WorkerManager.php b/src/SAREhub/Component/Worker/WorkerManager.php deleted file mode 100644 index e6c559f..0000000 --- a/src/SAREhub/Component/Worker/WorkerManager.php +++ /dev/null @@ -1,208 +0,0 @@ -uuid = $uuid; - } - - /** - * @param string $uuid - * @return WorkerManager - */ - public static function getNewWithUuid($uuid) { - return new self($uuid); - } - - /** - * @param CommandInput $commandInput - * @return $this - */ - public function commandInput(CommandInput $commandInput) { - $this->commandInput = $commandInput; - return $this; - } - - /** - * @param WorkerProcessFactory $factory - * @return $this - */ - public function workerProcessFactory(WorkerProcessFactory $factory) { - $this->workerProcessFactory = $factory; - return $this; - } - - public function onStart() { - - } - - public function onTick() { - if ($this->checkCommandReply()) { - if ($command = $this->commandInput->getNextCommand()) { - $this->processCommand($command); - } - } - } - - public function processCommand(Command $command) { - if ($command instanceof StartWorkerCommand) { - $this->startWorker($command->getUuid()); - $this->commandInput->sendCommandReply('1'); - return; - } - - if ($command instanceof StopWorkerCommand) { - $this->stopWorker($command->getUuid()); - return; - } - - throw new WorkerException('Unknown command: '.$command->getName()); - } - - /** - * Starting new worker process - * @param string $uuid - * @throws WorkerException - */ - public function startWorker($uuid) { - if ($this->hasWorkerProcess($uuid)) { - throw new WorkerException('Worker with that uuid is running: '.$uuid); - } - - $this->workerProcessList[$uuid] = $this->workerProcessFactory->create( - WorkerInfo::newInfo() - ->uuid($uuid) - ->startTime(time()) - ); - - $this->workerProcessList[$uuid]->start(); - } - - /** - * Stops all running workers - */ - public function stopAll() { - foreach ($this->workerProcessList as $uuid => $workerProcess) { - $this->stopWorker($uuid); - } - } - - public function stopWorker($uuid) { - if ($this->hasWorkerProcess($uuid)) { - $workerProcess = $this->getWorkerProcess($uuid); - $workerProcess->getCommandOutput()->sendCommand(new StopWorkerCommand($uuid)); - $this->waitingCommandReplyProcess = $workerProcess; - } - - } - - public function killAll() { - foreach ($this->workerProcessList as $uuid => $workerProcess) { - $this->killWorker($uuid); - } - } - - public function killWorker($uuid) { - if ($this->hasWorkerProcess($uuid)) { - $workerProcess = $this->getWorkerProcess($uuid); - $workerProcess->kill(); - } - } - - /** - * @param string $uuid - * @return WorkerProcess - */ - public function getWorkerProcess($uuid) { - return $this->workerProcessList[$uuid]; - } - - /** - * @return WorkerProcess[] - */ - public function getWorkerProcessList() { - return $this->workerProcessList; - } - - /** - * @param string $uuid - * @return bool - */ - public function hasWorkerProcess($uuid) { - return isset($this->workerProcessList[$uuid]); - } - - protected function checkCommandReply() { - if ($this->waitingCommandReplyProcess) { - $workerCommandOutput = $this->waitingCommandReplyProcess->getCommandOutput(); - if ($reply = $workerCommandOutput->getCommandReply()) { - $this->getCommandInput()->sendCommandReply($reply); - $this->waitingCommandReplyProcess = null; - } - return false; - } - - return true; - } - - public function isWaitingForCommandReplyFromWorker() { - return $this->waitingCommandReplyProcess != null; - } - - public function checkWorkersHealth() { - foreach ($this->workerProcessList as $workerProcess) { - if ($workerProcess->getProcess()->isRunning()) { - - } - } - } - - public function onStop() { - $this->stopAll(); - } - - public function onCommand(WorkerCommand $command) { - - } - - public function getUuid() { - return $this->uuid; - } - - /** - * @return CommandInput - */ - public function getCommandInput() { - return $this->commandInput; - } - -} \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Manager/WorkerCommandServiceTest.php b/tests/unit/SAREhub/Component/Worker/Manager/WorkerCommandServiceTest.php index cf012f6..c4ceec1 100644 --- a/tests/unit/SAREhub/Component/Worker/Manager/WorkerCommandServiceTest.php +++ b/tests/unit/SAREhub/Component/Worker/Manager/WorkerCommandServiceTest.php @@ -84,8 +84,7 @@ public function testSendCommandWhenReplyTimeout() { $command = new BasicCommand('c'); $this->outputMock->expects($this->once())->method('getCommandReply'); TimeProvider::get()->freezeTime(); - $this->service->setCommandReplyTimeout(0); - $reply = $this->service->sendCommand('id', $command); + $reply = $this->service->sendCommand('id', $command, 0); $this->assertEquals('reply timeout', $reply->getMessage()); TimeProvider::get()->unfreezeTime(); } diff --git a/tests/unit/SAREhub/Component/Worker/Manager/WorkerManagerTest.php b/tests/unit/SAREhub/Component/Worker/Manager/WorkerManagerTest.php new file mode 100644 index 0000000..956af81 --- /dev/null +++ b/tests/unit/SAREhub/Component/Worker/Manager/WorkerManagerTest.php @@ -0,0 +1,106 @@ +processServiceMock = $this->createMock(WorkerProcessService::class); + $this->commandServiceMock = $this->createMock(WorkerCommandService::class); + $this->manager = (new WorkerManager(WorkerContext::newInstance())) + ->withProcessService($this->processServiceMock) + ->withCommandService($this->commandServiceMock); + } + + public function testStartCommandWhenNotExistsThenSuccess() { + $workerId = 'worker1'; + $command = ManagerCommands::start($workerId); + $reply = $this->manager->processCommand($command); + $this->assertTrue($reply->isSuccess()); + } + + public function testStartCommandWhenNotExistsThenRegisterInProcessService() { + $workerId = 'worker1'; + $command = ManagerCommands::start($workerId); + $this->processServiceMock->expects($this->once())->method('register')->with($workerId); + $this->manager->processCommand($command); + } + + public function testStartCommandWhenNotExistsThenStartInProcessService() { + $workerId = 'worker1'; + $command = ManagerCommands::start($workerId); + $this->processServiceMock->expects($this->once())->method('start')->with($workerId); + $this->manager->processCommand($command); + } + + public function testStartCommandWhenNotExistsThenRegisterInCommandService() { + $workerId = 'worker1'; + $command = ManagerCommands::start($workerId); + $this->commandServiceMock->expects($this->once())->method('register')->with($workerId); + $this->manager->processCommand($command); + } + + public function testStartCommandWhenExistsThenError() { + $workerId = 'worker1'; + $command = ManagerCommands::start($workerId); + $this->processServiceMock->method('has')->with($workerId)->willReturn(true); + $reply = $this->manager->processCommand($command); + $this->assertTrue($reply->isError()); + } + + public function testStartWorkerCommandWhenExistsThenNotRegisterInProcessService() { + $workerId = 'worker1'; + $command = ManagerCommands::start($workerId); + $this->processServiceMock->method('has')->with($workerId)->willReturn(true); + $this->processServiceMock->expects($this->never())->method('register'); + $this->manager->processCommand($command); + } + + public function testStartWorkerCommandWhenExistsThenNotRegisterInCommandService() { + $workerId = 'worker1'; + $command = ManagerCommands::start($workerId); + $this->processServiceMock->method('has')->with($workerId)->willReturn(true); + $this->commandServiceMock->expects($this->never())->method('register'); + $this->manager->processCommand($command); + } + + public function testStopWorkerCommandWhenExistsThenSendCommand() { + $command = ManagerCommands::stop('worker1'); + $this->commandServiceMock->expects($this->once())->method('sendCommand') + ->with('worker1', $this->callback(function (Command $command) { + return $command->getName() === WorkerCommands::STOP; + }))->willReturn(CommandReply::success('reply')); + $this->manager->processCommand($command); + } + + public function testStopWorkerCommandWhenExistsThenReturnReply() { + $command = ManagerCommands::stop('worker1'); + $expectedReply = CommandReply::success('reply'); + $this->commandServiceMock->method('sendCommand')->willReturn($expectedReply); + $this->assertSame($expectedReply, $this->manager->processCommand($command)); + } +} diff --git a/tests/unit/SAREhub/Component/Worker/WorkerManagerTest.php b/tests/unit/SAREhub/Component/Worker/WorkerManagerTest.php deleted file mode 100644 index 1d280d0..0000000 --- a/tests/unit/SAREhub/Component/Worker/WorkerManagerTest.php +++ /dev/null @@ -1,66 +0,0 @@ -workerProcessMock = $this->createMock(WorkerProcess::class); - $this->workerProcessMock->method('getWorkerUuid')->willReturn($this->workerUuid); - $this->workerCommandOutputMock = $this->createMock(CommandOutput::class); - $this->workerProcessMock->method('getCommandOutput')->willReturn($this->workerCommandOutputMock); - - $this->workerProcessFactoryMock = $this->createMock(WorkerProcessFactory::class); - $this->workerProcessFactoryMock->method('create')->willReturn($this->workerProcessMock); - $this->commandInputMock = $this->createMock(CommandInput::class); - $this->workerManager = WorkerManager::getNewWithUuid('manager') - ->workerProcessFactory($this->workerProcessFactoryMock); - } - - public function testStartWorker() { - $this->workerProcessFactoryMock->expects($this->once()) - ->method('create')->with($this->isInstanceOf(WorkerInfo::class)) - ->willReturn($this->workerProcessMock); - $this->workerProcessMock->expects($this->once())->method('start'); - $this->workerManager->startWorker($this->workerUuid); - $this->assertEquals([ - $this->workerUuid => $this->workerProcessMock - ], $this->workerManager->getWorkerProcessList()); - } - - public function testStopWorker() { - $this->workerManager->startWorker($this->workerUuid); - $this->workerCommandOutputMock->expects($this->once()) - ->method('sendCommand') - ->with(new StopWorkerCommand($this->workerUuid)); - - $this->assertFalse($this->workerManager->isWaitingForCommandReplyFromWorker()); - $this->workerManager->stopWorker($this->workerUuid); - $this->assertTrue($this->workerManager->isWaitingForCommandReplyFromWorker()); - } -} From d84d9892e7b6df73e1fe1dc622c2befb75ea91a9 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Tue, 11 Oct 2016 11:01:58 +0200 Subject: [PATCH 065/133] fixes --- .../Component/Worker/Manager/WorkerProcessService.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/SAREhub/Component/Worker/Manager/WorkerProcessService.php b/src/SAREhub/Component/Worker/Manager/WorkerProcessService.php index 1674b4b..7ea8899 100644 --- a/src/SAREhub/Component/Worker/Manager/WorkerProcessService.php +++ b/src/SAREhub/Component/Worker/Manager/WorkerProcessService.php @@ -70,6 +70,14 @@ protected function get($id) { return $this->has($id) ? $this->processList[$id] : null; } + /** + * @param $id + * @return boolean + */ + public function isWorkerRunning($id) { + return $this->get($id)->isRunning(); + } + /** * @param string $id * @return bool From c8d5797c71619b1fa67b35f417a82a766321db4d Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Tue, 11 Oct 2016 11:03:41 +0200 Subject: [PATCH 066/133] removed namespace from tests --- .../SAREhub/Component/Worker/Command/BasicCommandTest.php | 2 +- .../Component/Worker/Command/JsonCommandFormatTest.php | 3 ++- .../SAREhub/Component/Worker/Command/ZmqCommandInputTest.php | 5 +++-- .../Component/Worker/Command/ZmqCommandOutputTest.php | 5 +++-- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/tests/unit/SAREhub/Component/Worker/Command/BasicCommandTest.php b/tests/unit/SAREhub/Component/Worker/Command/BasicCommandTest.php index 4eeff0d..191c1dc 100644 --- a/tests/unit/SAREhub/Component/Worker/Command/BasicCommandTest.php +++ b/tests/unit/SAREhub/Component/Worker/Command/BasicCommandTest.php @@ -1,8 +1,8 @@ Date: Tue, 11 Oct 2016 11:18:34 +0200 Subject: [PATCH 067/133] only php 7 --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e44ed7b..5a88691 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ sudo: false language: php php: -- 5.6 - 7.0 branches: only: From b8f4387298d99129d49592d1c3d20fd3b0d7ad60 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Tue, 11 Oct 2016 11:18:46 +0200 Subject: [PATCH 068/133] only php 7 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index e023048..c172bb3 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ "phpdocumentor/phpdocumentor": "2.*" }, "require": { - "php": "^5.6 || ^7.0", + "php": "^7.0", "symfony/process": "3.1.3 as 2.8.9", "sarehub/commons": "0.5.*", "respect/validation": "1.1.*" From 7b8090f4a268a9f09bf60711f5528ccc73cbb7ed Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Tue, 11 Oct 2016 11:46:03 +0200 Subject: [PATCH 069/133] added tests for factory --- .../Worker/Command/ZmqCommandOutput.php | 15 +++++- .../Command/ZmqCommandOutputFactory.php | 30 +++++++----- .../Command/ZmqCommandOutputFactoryTest.php | 46 +++++++++++++++++++ 3 files changed, 79 insertions(+), 12 deletions(-) create mode 100644 tests/unit/SAREhub/Component/Worker/Command/ZmqCommandOutputFactoryTest.php diff --git a/src/SAREhub/Component/Worker/Command/ZmqCommandOutput.php b/src/SAREhub/Component/Worker/Command/ZmqCommandOutput.php index 397a343..5979cf9 100644 --- a/src/SAREhub/Component/Worker/Command/ZmqCommandOutput.php +++ b/src/SAREhub/Component/Worker/Command/ZmqCommandOutput.php @@ -2,7 +2,6 @@ namespace SAREhub\Component\Worker\Command; - use SAREhub\Commons\Zmq\RequestReply\RequestSender; class ZmqCommandOutput implements CommandOutput { @@ -60,4 +59,18 @@ public function isInBlockingMode() { public function close() { $this->sender->disconnect(); } + + /** + * @return RequestSender + */ + public function getSender() { + return $this->sender; + } + + /** + * @return CommandFormat + */ + public function getCommandFormat() { + return $this->format; + } } \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Command/ZmqCommandOutputFactory.php b/src/SAREhub/Component/Worker/Command/ZmqCommandOutputFactory.php index 4fa386e..71b045a 100644 --- a/src/SAREhub/Component/Worker/Command/ZmqCommandOutputFactory.php +++ b/src/SAREhub/Component/Worker/Command/ZmqCommandOutputFactory.php @@ -6,23 +6,31 @@ class ZmqCommandOutputFactory implements CommandOutputFactory { + private $senderFactory; private $format; - private $zmqContext; /** - * @var callable + * @param callable $senderFactory + * @param CommandFormat $format */ - private $dsnFactory; - - public function __construct(CommandFormat $format, \ZMQContext $context, callable $dsnFactory) { + public function __construct(callable $senderFactory, CommandFormat $format) { + $this->senderFactory = $senderFactory; $this->format = $format; - $this->zmqContext = $context; - $this->dsnFactory = $dsnFactory; } - public function create($workerUuid) { - $sender = RequestSender::inContext($this->zmqContext) - ->connect(($this->dsnFactory)($workerUuid)); - return new ZmqCommandOutput($sender, $this->format); + public function create($workerId) { + return new ZmqCommandOutput(($this->senderFactory)($workerId), $this->format); + } + + + /** + * @param \ZMQContext $context + * @param callable $dsnFactory + * @return \Closure + */ + public static function getSenderFactory(\ZMQContext $context, callable $dsnFactory) { + return function ($workerId) use ($context, $dsnFactory) { + return RequestSender::inContext($context)->connect(($dsnFactory)($workerId)); + }; } } \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandOutputFactoryTest.php b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandOutputFactoryTest.php new file mode 100644 index 0000000..9ce48a8 --- /dev/null +++ b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandOutputFactoryTest.php @@ -0,0 +1,46 @@ +commandFormatMock = $this->createMock(CommandFormat::class); + $this->senderMock = $this->createMock(RequestSender::class); + $this->senderFactoryMock = $this->getMockBuilder(stdClass::class)->setMethods(['__invoke'])->getMock(); + $this->senderFactoryMock->method('__invoke')->willReturn($this->senderMock); + $this->factory = new ZmqCommandOutputFactory($this->senderFactoryMock, $this->commandFormatMock); + } + + public function testCreateThenCreateCallSenderFactory() { + $workerId = 'worker1'; + $this->senderFactoryMock->expects($this->once())->method('__invoke') + ->with($workerId)->willReturn($this->senderMock); + $this->factory->create($workerId); + } + + public function testCreateThenReturnOutput() { + $this->assertInstanceOf(ZmqCommandOutput::class, $this->factory->create('workerId')); + } + + public function testCreateThenSenderSets() { + $output = $this->factory->create('worker1'); + $this->assertSame($this->senderMock, $output->getSender()); + } + + public function testCreateThenCommandFormatSets() { + $output = $this->factory->create('worker1'); + $this->assertSame($this->commandFormatMock, $output->getCommandFormat()); + } +} From 33965688862cb960b3bd9ba006039de7d8be773e Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Wed, 12 Oct 2016 16:50:05 +0200 Subject: [PATCH 070/133] extracted command reply output interface --- .../Component/Worker/Command/CommandInput.php | 11 ++--- .../Worker/Command/CommandReplyOutput.php | 20 ++++++++ .../Worker/Command/ZmqCommandReplyOutput.php | 40 ++++++++++++++++ .../Command/ZmqCommandReplyOutputTest.php | 47 +++++++++++++++++++ 4 files changed, 110 insertions(+), 8 deletions(-) create mode 100644 src/SAREhub/Component/Worker/Command/CommandReplyOutput.php create mode 100644 src/SAREhub/Component/Worker/Command/ZmqCommandReplyOutput.php create mode 100644 tests/unit/SAREhub/Component/Worker/Command/ZmqCommandReplyOutputTest.php diff --git a/src/SAREhub/Component/Worker/Command/CommandInput.php b/src/SAREhub/Component/Worker/Command/CommandInput.php index be219bb..6897528 100644 --- a/src/SAREhub/Component/Worker/Command/CommandInput.php +++ b/src/SAREhub/Component/Worker/Command/CommandInput.php @@ -9,15 +9,10 @@ interface CommandInput { /** * Gets next command from input or returns null when no command. - * @return Command|null + * @param bool $wait + * @return null|Command */ - public function getNextCommand(); - - /** - * Sends reply for processed command - * @param string $reply - */ - public function sendCommandReply($reply); + public function getNextCommand($wait = false); /** * Will close command input diff --git a/src/SAREhub/Component/Worker/Command/CommandReplyOutput.php b/src/SAREhub/Component/Worker/Command/CommandReplyOutput.php new file mode 100644 index 0000000..c37c327 --- /dev/null +++ b/src/SAREhub/Component/Worker/Command/CommandReplyOutput.php @@ -0,0 +1,20 @@ +publisher = $publisher; + $this->publishTopic = $publishTopic; + } + + public function send(Command $command, CommandReply $reply, $wait = false) { + $this->getPublisher()->publish($this->getPublishTopic(), $reply->toJson(), $wait); + } + + public function close() { + $this->publisher->unbind(); + } + + public function getPublisher() { + return $this->publisher; + } + + public function getPublishTopic() { + return $this->publishTopic; + } +} \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandReplyOutputTest.php b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandReplyOutputTest.php new file mode 100644 index 0000000..d2608a4 --- /dev/null +++ b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandReplyOutputTest.php @@ -0,0 +1,47 @@ +publisher = $this->createMock(Publisher::class); + $this->output = new ZmqCommandReplyOutput($this->publisher, $this->topic); + } + + public function testSendThenPublisherPublish() { + $reply = CommandReply::success("reply"); + $this->publisher->expects($this->once())->method('publish') + ->with($this->topic, $reply->toJson(), false); + $this->output->send(new BasicCommand("name"), $reply); + } + + public function testSendWhenWaitThenPublisherPublishWithWait() { + $reply = CommandReply::success("reply"); + $this->publisher->expects($this->once())->method('publish') + ->with($this->topic, $reply->toJson(), true); + $this->output->send(new BasicCommand("name"), $reply, true); + } + + public function testClose() { + $this->publisher->expects($this->once())->method('unbind'); + $this->output->close(); + } +} From b603d310b93ba16b94628ba73c681eaa1d2d5038 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Wed, 12 Oct 2016 16:50:38 +0200 Subject: [PATCH 071/133] added toJson method --- src/SAREhub/Component/Worker/Command/CommandReply.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/SAREhub/Component/Worker/Command/CommandReply.php b/src/SAREhub/Component/Worker/Command/CommandReply.php index 5fdf996..cb71cc9 100644 --- a/src/SAREhub/Component/Worker/Command/CommandReply.php +++ b/src/SAREhub/Component/Worker/Command/CommandReply.php @@ -114,4 +114,11 @@ public function jsonSerialize() { 'data' => $this->getData() ]; } + + /** + * @return string + */ + public function toJson() { + return json_encode($this); + } } \ No newline at end of file From e50217809b70d8743edd030afd901b953876f19a Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Wed, 12 Oct 2016 16:52:35 +0200 Subject: [PATCH 072/133] fixes for subscriber --- .../Component/Worker/Command/CommandInput.php | 2 +- .../Worker/Command/ZmqCommandInput.php | 70 ++++--------------- .../Worker/Command/ZmqCommandInputTest.php | 61 +++++++--------- 3 files changed, 39 insertions(+), 94 deletions(-) diff --git a/src/SAREhub/Component/Worker/Command/CommandInput.php b/src/SAREhub/Component/Worker/Command/CommandInput.php index 6897528..ee3b7d0 100644 --- a/src/SAREhub/Component/Worker/Command/CommandInput.php +++ b/src/SAREhub/Component/Worker/Command/CommandInput.php @@ -12,7 +12,7 @@ interface CommandInput { * @param bool $wait * @return null|Command */ - public function getNextCommand($wait = false); + public function getNext($wait = false); /** * Will close command input diff --git a/src/SAREhub/Component/Worker/Command/ZmqCommandInput.php b/src/SAREhub/Component/Worker/Command/ZmqCommandInput.php index 7d2bb9f..170f082 100644 --- a/src/SAREhub/Component/Worker/Command/ZmqCommandInput.php +++ b/src/SAREhub/Component/Worker/Command/ZmqCommandInput.php @@ -2,7 +2,7 @@ namespace SAREhub\Component\Worker\Command; -use SAREhub\Commons\Zmq\RequestReply\RequestReceiver; +use SAREhub\Commons\Zmq\PublishSubscribe\Subscriber; /** * Worker command input based on ZMQ Request/Reply method @@ -11,78 +11,34 @@ class ZmqCommandInput implements CommandInput { /** - * @var RequestReceiver + * @var Subscriber */ - protected $receiver; - - /** - * @var bool - */ - protected $blockingMode = false; + private $commandSubscriber; /** * @var CommandFormat */ private $format; - /** - * @var Command - */ - private $lastCommand = null; - public function __construct(RequestReceiver $receiver, CommandFormat $format) { - $this->receiver = $receiver; + public function __construct(Subscriber $commandSubscriber, CommandFormat $format) { + $this->commandSubscriber = $commandSubscriber; $this->format = $format; } - /** - * Sets blocking mode for getNextCommand - will waits for next command - * @return $this - */ - public function blockingMode() { - $this->blockingMode = true; - return $this; + public function getNext($wait = false) { + $commandData = $this->getCommandSubscriber()->receive($wait); + return ($commandData) ? $this->format->unmarshal($commandData['body']) : null; } - /** - * @return $this - */ - public function nonBlockingMode() { - $this->blockingMode = false; - return $this; - } - - public function getNextCommand() { - if ($this->lastCommand) { - throw new CommandException( - "Can't get next command, when reply for last wasn't sent, last command was: ".$this->lastCommand - ); - } - - $commandData = $this->receiver->receiveRequest($this->isInBlockingMode()); - $this->lastCommand = ($commandData) ? $this->format->unmarshal($commandData) : null; - return $this->lastCommand; - } - - public function sendCommandReply($reply) { - if ($this->lastCommand === null) { - throw new CommandException("Reply can be sent only when receive command"); - } - $this->receiver->sendReply($reply, $this->isInBlockingMode()); - $this->lastCommand = null; - } - - /** - * @return bool - */ - public function isInBlockingMode() { - return $this->blockingMode; + public function close() { + $this->getCommandSubscriber()->disconnect(); } /** - * Will close command input + * @return Subscriber */ - public function close() { - $this->receiver->unbind(); + public function getCommandSubscriber() { + return $this->commandSubscriber; } } \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandInputTest.php b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandInputTest.php index e5e963b..2af9d0d 100644 --- a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandInputTest.php +++ b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandInputTest.php @@ -2,7 +2,7 @@ use PHPUnit\Framework\TestCase; -use SAREhub\Commons\Zmq\RequestReply\RequestReceiver; +use SAREhub\Commons\Zmq\PublishSubscribe\Subscriber; use SAREhub\Component\Worker\Command\BasicCommand; use SAREhub\Component\Worker\Command\CommandFormat; use SAREhub\Component\Worker\Command\ZmqCommandInput; @@ -12,7 +12,7 @@ class ZmqCommandInputTest extends TestCase { /** * @var PHPUnit_Framework_MockObject_MockObject */ - private $receiverMock; + private $subscriberMock; /** * @var PHPUnit_Framework_MockObject_MockObject @@ -24,57 +24,46 @@ class ZmqCommandInputTest extends TestCase { */ private $commandInput; - private $commandData = 'command_data'; + private $commandData = ['topic' => 'command', 'body' => 'data']; protected function setUp() { - $this->receiverMock = $this->createMock(RequestReceiver::class); + $this->subscriberMock = $this->createMock(Subscriber::class); $this->commandFormatMock = $this->createMock(CommandFormat::class); - $this->commandInput = new ZmqCommandInput($this->receiverMock, $this->commandFormatMock); + $this->commandInput = new ZmqCommandInput($this->subscriberMock, $this->commandFormatMock); } - public function testGetNextCommandWhenNonBlockingMode() { - $command = new BasicCommand('name'); - $this->receiverMock->method('receiveRequest') - ->with(false)->willReturn($this->commandData); - $this->commandFormatMock->expects($this->once())->method('unmarshal') - ->with($this->commandData)->willReturn($command); - $this->assertSame($command, $this->commandInput->getNextCommand()); + public function testGetNextThenSubscriberReceive() { + $this->subscriberMock->expects($this->once())->method('receive')->with(false); + $this->commandInput->getNext(); } - public function testGetNextCommandWhenBlockingMode() { - $command = new BasicCommand('name'); - $this->receiverMock->method('receiveRequest')->with(true)->willReturn($this->commandData); + public function testGetNextWhenCommandThenCommandFormatUnmarshal() { + $this->subscriberMock->method('receive')->willReturn($this->commandData); $this->commandFormatMock->expects($this->once())->method('unmarshal') - ->with($this->commandData)->willReturn($command); - $this->assertSame($command, $this->commandInput->blockingMode()->getNextCommand()); + ->with($this->commandData['body']); + $this->commandInput->getNext(); } - public function testGetNextCommandWhenNotSent() { - $this->receiverMock->expects($this->once())->method('receiveRequest')->willReturn(false); - $this->commandFormatMock->expects($this->never())->method('unmarshal'); - $this->assertNull($this->commandInput->getNextCommand()); + public function testGetNextWhenCommandThenReturnCommand() { + $command = new BasicCommand("test"); + $this->subscriberMock->method('receive')->willReturn($this->commandData); + $this->commandFormatMock->method('unmarshal')->willReturn($command); + $this->assertSame($command, $this->commandInput->getNext()); } - public function testSendReplyWhenCommandWasReceive() { - $this->receiverMock->method('receiveRequest')->willReturn('c'); - $this->commandFormatMock->method('unmarshal')->willReturn(new BasicCommand('c')); - $this->commandInput->getNextCommand(); - - $this->receiverMock->expects($this->once())->method('sendReply')->with('reply', false); - $this->commandInput->sendCommandReply('reply'); + public function testGetNextWhenWaitThenReceiveInWait() { + $this->subscriberMock->method('receive')->with(true); + $this->commandInput->getNext(true); } - public function testSendReplyBlocking() { - $this->receiverMock->method('receiveRequest')->willReturn('c'); - $this->commandFormatMock->method('unmarshal')->willReturn(new BasicCommand('c')); - $this->commandInput->getNextCommand(); - - $this->receiverMock->expects($this->once())->method('sendReply')->with('reply', true); - $this->commandInput->blockingMode()->sendCommandReply('reply'); + public function testGetNextWhenNotSent() { + $this->subscriberMock->method('receive')->willReturn(false); + $this->commandFormatMock->expects($this->never())->method('unmarshal'); + $this->assertNull($this->commandInput->getNext()); } public function testClose() { - $this->receiverMock->expects($this->once())->method('unbind'); + $this->subscriberMock->expects($this->once())->method('disconnect'); $this->commandInput->close(); } } From 9f02c26b016f8fef3ead9f10c510e7571689c899 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Wed, 12 Oct 2016 16:52:51 +0200 Subject: [PATCH 073/133] fixes --- src/SAREhub/Component/Worker/Command/BasicCommand.php | 2 +- .../unit/SAREhub/Component/Worker/Command/BasicCommandTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SAREhub/Component/Worker/Command/BasicCommand.php b/src/SAREhub/Component/Worker/Command/BasicCommand.php index 658157b..efd5aaf 100644 --- a/src/SAREhub/Component/Worker/Command/BasicCommand.php +++ b/src/SAREhub/Component/Worker/Command/BasicCommand.php @@ -30,7 +30,7 @@ public function getParameters() { } public function __toString() { - return __CLASS__.':'.json_encode([ + return 'COMMAND:'.json_encode([ 'name' => $this->getName(), 'parameters' => $this->getParameters() ]); diff --git a/tests/unit/SAREhub/Component/Worker/Command/BasicCommandTest.php b/tests/unit/SAREhub/Component/Worker/Command/BasicCommandTest.php index 191c1dc..a43fe0a 100644 --- a/tests/unit/SAREhub/Component/Worker/Command/BasicCommandTest.php +++ b/tests/unit/SAREhub/Component/Worker/Command/BasicCommandTest.php @@ -28,6 +28,6 @@ public function testToString() { 'param1' => 1 ] ]); - $this->assertEquals(BasicCommand::class.':'.$expectedJson, (string)$command); + $this->assertEquals('COMMAND:'.$expectedJson, (string)$command); } } From c683c45f527c1bc9706ccfc123b6d9aaa95cdba5 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Thu, 13 Oct 2016 09:26:29 +0200 Subject: [PATCH 074/133] added correlation_id to command --- .../Component/Worker/Command/BasicCommand.php | 12 ++++- .../Component/Worker/Command/Command.php | 2 + .../Worker/Command/JsonCommandFormat.php | 8 +++- .../Worker/Command/JsonCommandFormatTest.php | 45 ++++++++++--------- 4 files changed, 45 insertions(+), 22 deletions(-) diff --git a/src/SAREhub/Component/Worker/Command/BasicCommand.php b/src/SAREhub/Component/Worker/Command/BasicCommand.php index efd5aaf..5abc04b 100644 --- a/src/SAREhub/Component/Worker/Command/BasicCommand.php +++ b/src/SAREhub/Component/Worker/Command/BasicCommand.php @@ -7,14 +7,23 @@ */ class BasicCommand implements Command { + private $correlationId; private $name; private $parameters; - public function __construct($name, array $parameters = null) { + public function __construct($correlationId, $name, array $parameters = null) { + $this->correlationId = $correlationId; $this->name = $name; $this->parameters = empty($parameters) ? [] : $parameters; } + /** + * @return string + */ + public function getCorrelationId() { + return $this->correlationId; + } + /** * @return string */ @@ -31,6 +40,7 @@ public function getParameters() { public function __toString() { return 'COMMAND:'.json_encode([ + 'correlation_id' => $this->getCorrelationId(), 'name' => $this->getName(), 'parameters' => $this->getParameters() ]); diff --git a/src/SAREhub/Component/Worker/Command/Command.php b/src/SAREhub/Component/Worker/Command/Command.php index a616098..5689fe2 100644 --- a/src/SAREhub/Component/Worker/Command/Command.php +++ b/src/SAREhub/Component/Worker/Command/Command.php @@ -7,6 +7,8 @@ */ interface Command { + public function getCorrelationId(); + /** * @return string */ diff --git a/src/SAREhub/Component/Worker/Command/JsonCommandFormat.php b/src/SAREhub/Component/Worker/Command/JsonCommandFormat.php index abe48d9..756c1ec 100644 --- a/src/SAREhub/Component/Worker/Command/JsonCommandFormat.php +++ b/src/SAREhub/Component/Worker/Command/JsonCommandFormat.php @@ -4,6 +4,7 @@ class JsonCommandFormat implements CommandFormat { + const CORRELATION_ID_INDEX = 'correlation_id'; const NAME_INDEX = 'name'; const PARAMETERS_INDEX = 'parameters'; @@ -16,6 +17,7 @@ public static function newInstance() { public function marshal(Command $command) { return json_encode([ + self::CORRELATION_ID_INDEX => $command->getCorrelationId(), self::NAME_INDEX => $command->getName(), self::PARAMETERS_INDEX => $command->getParameters() ]); @@ -23,6 +25,10 @@ public function marshal(Command $command) { public function unmarshal($commandData) { $commandData = json_decode($commandData, true); - return new BasicCommand($commandData[self::NAME_INDEX], $commandData[self::PARAMETERS_INDEX]); + return new BasicCommand( + $commandData[self::CORRELATION_ID_INDEX], + $commandData[self::NAME_INDEX], + $commandData[self::PARAMETERS_INDEX] + ); } } \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Command/JsonCommandFormatTest.php b/tests/unit/SAREhub/Component/Worker/Command/JsonCommandFormatTest.php index 1aa74ec..9dfee78 100644 --- a/tests/unit/SAREhub/Component/Worker/Command/JsonCommandFormatTest.php +++ b/tests/unit/SAREhub/Component/Worker/Command/JsonCommandFormatTest.php @@ -7,30 +7,35 @@ class JsonCommandFormatTest extends TestCase { - public function testMarshal() { - $command = new BasicCommand('name1', ['param1' => 'value']); - $expectedJson = json_encode( - [ - 'name' => 'name1', - 'parameters' => [ - 'param1' => 'value' - ] - ]); + private $commandJson; + + /** + * @var JsonCommandFormat + */ + private $format; + + protected function setUp() { + parent::setUp(); + $this->commandJson = json_encode([ + JsonCommandFormat::CORRELATION_ID_INDEX => '1', + JsonCommandFormat::NAME_INDEX => 'name1', + JsonCommandFormat::PARAMETERS_INDEX => [ + 'param1' => 'value' + ] + ]); - $this->assertEquals($expectedJson, JsonCommandFormat::newInstance()->marshal($command)); + $this->format = JsonCommandFormat::newInstance(); + } + + public function testMarshal() { + $command = new BasicCommand('1', 'name1', ['param1' => 'value']); + $this->assertEquals($this->commandJson, $this->format->marshal($command)); } public function testUnmarshal() { - $command = JsonCommandFormat::newInstance()->unmarshal(json_encode( - [ - 'name' => 'name1', - 'parameters' => [ - 'param1' => 1 - ] - ] - )); - + $command = $this->format->unmarshal($this->commandJson); + $this->assertEquals('1', $command->getCorrelationId()); $this->assertEquals('name1', $command->getName()); - $this->assertEquals(['param1' => 1], $command->getParameters()); + $this->assertEquals(['param1' => 'value'], $command->getParameters()); } } From f17372239de15fe1ad449f6a063717f166aee98c Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Thu, 13 Oct 2016 09:27:40 +0200 Subject: [PATCH 075/133] fix tests --- .../SAREhub/Component/Worker/Command/BasicCommandTest.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/unit/SAREhub/Component/Worker/Command/BasicCommandTest.php b/tests/unit/SAREhub/Component/Worker/Command/BasicCommandTest.php index a43fe0a..e262fbb 100644 --- a/tests/unit/SAREhub/Component/Worker/Command/BasicCommandTest.php +++ b/tests/unit/SAREhub/Component/Worker/Command/BasicCommandTest.php @@ -7,22 +7,24 @@ class BasicCommandTest extends TestCase { public function testCreateWithoutParameters() { - $command = new BasicCommand('name'); + $command = new BasicCommand('1', 'name'); + $this->assertEquals('1', $command->getCorrelationId()); $this->assertEquals('name', $command->getName()); $this->assertEquals([], $command->getParameters()); } public function testCreateWithParameters() { $parameters = ['param1' => 1]; - $command = new BasicCommand('name', $parameters); + $command = new BasicCommand('1', 'name', $parameters); $this->assertEquals('name', $command->getName()); $this->assertEquals($parameters, $command->getParameters()); } public function testToString() { - $command = new BasicCommand('name1', ['param1' => 1]); + $command = new BasicCommand('1', 'name1', ['param1' => 1]); $expectedJson = json_encode([ + 'correlation_id' => '1', 'name' => 'name1', 'parameters' => [ 'param1' => 1 From 2e2e707cf3b8f3f3dbf9d8e0b7be27e341e8e8a7 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Thu, 13 Oct 2016 09:28:31 +0200 Subject: [PATCH 076/133] fix tests for correlation_id --- .../SAREhub/Component/Worker/Command/ZmqCommandInputTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandInputTest.php b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandInputTest.php index 2af9d0d..f982afa 100644 --- a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandInputTest.php +++ b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandInputTest.php @@ -45,7 +45,7 @@ public function testGetNextWhenCommandThenCommandFormatUnmarshal() { } public function testGetNextWhenCommandThenReturnCommand() { - $command = new BasicCommand("test"); + $command = new BasicCommand('1', "test"); $this->subscriberMock->method('receive')->willReturn($this->commandData); $this->commandFormatMock->method('unmarshal')->willReturn($command); $this->assertSame($command, $this->commandInput->getNext()); From a65aa773f65ccf00e5321d513b6be88bad7ff52c Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Thu, 13 Oct 2016 09:28:56 +0200 Subject: [PATCH 077/133] refactored --- .../Component/Worker/Command/CommandOutput.php | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/SAREhub/Component/Worker/Command/CommandOutput.php b/src/SAREhub/Component/Worker/Command/CommandOutput.php index 7432d4d..e9890e3 100644 --- a/src/SAREhub/Component/Worker/Command/CommandOutput.php +++ b/src/SAREhub/Component/Worker/Command/CommandOutput.php @@ -9,17 +9,12 @@ interface CommandOutput { /** * Sends command to output. + * @param $topic * @param Command $command - * @throws CommandException + * @param bool $wait + * @return */ - public function sendCommand(Command $command); - - /** - * Gets reply for sent command if available or return nulll. - * @return string|null - * @throws CommandException - */ - public function getCommandReply(); + public function send($topic, Command $command, $wait = false); /** * Will close output of command From 2b42e4a9aec751db643528b1dc4ec54a6c276174 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Thu, 13 Oct 2016 09:40:03 +0200 Subject: [PATCH 078/133] refactored --- .../Worker/Command/ZmqCommandOutput.php | 60 ++++------------ .../Worker/Command/ZmqCommandOutputTest.php | 70 +++++++------------ 2 files changed, 42 insertions(+), 88 deletions(-) diff --git a/src/SAREhub/Component/Worker/Command/ZmqCommandOutput.php b/src/SAREhub/Component/Worker/Command/ZmqCommandOutput.php index 5979cf9..45c38f9 100644 --- a/src/SAREhub/Component/Worker/Command/ZmqCommandOutput.php +++ b/src/SAREhub/Component/Worker/Command/ZmqCommandOutput.php @@ -2,69 +2,39 @@ namespace SAREhub\Component\Worker\Command; -use SAREhub\Commons\Zmq\RequestReply\RequestSender; +use SAREhub\Commons\Zmq\PublishSubscribe\Publisher; class ZmqCommandOutput implements CommandOutput { - private $sender; - private $blockingMode = false; - private $format; - - public function __construct(RequestSender $sender, CommandFormat $format) { - $this->sender = $sender; - $this->format = $format; - } - /** - * @return $this + * @var Publisher */ - public function blockingMode() { - $this->blockingMode = true; - return $this; - } + private $publisher; /** - * @return $this + * @var CommandFormat */ - public function nonBlockingMode() { - $this->blockingMode = true; - return $this; - } - - public function sendCommand(Command $command) { - $commandData = $this->format->marshal($command); - try { - $this->sender->sendRequest($commandData, $this->isInBlockingMode()); - } catch (\ZMQException $e) { - throw new CommandException("send command: ".$command, 0, $e); - } - } - + private $format; - public function getCommandReply() { - try { - return $this->sender->receiveReply($this->isInBlockingMode()); - } catch (\ZMQException $e) { - throw new CommandException("get command reply ", $e); - } + public function __construct(Publisher $publisher, CommandFormat $format) { + $this->publisher = $publisher; + $this->format = $format; } - public function isInBlockingMode() { - return $this->blockingMode; + public function send($topic, Command $command, $wait = false) { + $commandData = $this->format->marshal($command); + $this->getPublisher()->publish($topic, $commandData, $wait); } - /** - * Will close output of command - */ public function close() { - $this->sender->disconnect(); + $this->getPublisher()->unbind(); } /** - * @return RequestSender + * @return Publisher */ - public function getSender() { - return $this->sender; + public function getPublisher() { + return $this->publisher; } /** diff --git a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandOutputTest.php b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandOutputTest.php index 8770b90..9ef8c86 100644 --- a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandOutputTest.php +++ b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandOutputTest.php @@ -1,65 +1,49 @@ senderMock = $this->createMock(RequestSender::class); - $this->formatMock = $this->createMock(CommandFormat::class); - $this->commandOutput = new ZmqCommandOutput($this->senderMock, $this->formatMock); - } - - public function testSendCommandWhenNonBlockingMode() { - $command = new BasicCommand('c'); - $commandData = 'c'; - $this->senderMock->expects($this->once())->method('sendRequest') - ->with($commandData, false); - $this->formatMock->expects($this->once())->method('marshal') - ->with($this->identicalTo($command))->willReturn($commandData); - - $this->commandOutput->sendCommand($command); + parent::setUp(); + $this->publisher = $this->createMock(Publisher::class); + $this->commandFormat = $this->createMock(CommandFormat::class); + $this->commandFormat->method('marshal')->willReturn('command_data'); + $this->output = new ZmqCommandOutput($this->publisher, $this->commandFormat); } - public function testSendWhenBlockingMode() { - $command = new BasicCommand('c'); - $commandData = 'c'; - $this->senderMock->expects($this->once())->method('sendRequest') - ->with($commandData, true); - $this->formatMock->expects($this->once())->method('marshal') - ->with($this->identicalTo($command))->willReturn($commandData); - - $this->commandOutput->blockingMode()->sendCommand($command); + public function testSendThenPublisherCallPublish() { + $this->publisher->expects($this->once())->method('publish')->with('topic', 'command_data', false); + $this->output->send('topic', new BasicCommand('1', 'test')); } - public function testGetCommandReplyWhenNonBlockingMode() { - $this->senderMock->expects($this->once())->method('receiveReply') - ->with(false)->willReturn('reply'); - $this->assertEquals('reply', $this->commandOutput->getCommandReply()); + public function testSendWhenWaitThenPublisherPublishWait() { + $this->publisher->expects($this->once())->method('publish')->with('topic', 'command_data', true); + $this->output->send('topic', new BasicCommand('1', 'test'), true); } - public function testGetCommandReplyWhenBlockingMode() { - $this->senderMock->expects($this->once())->method('receiveReply') - ->with(true)->willReturn('reply'); - $this->assertEquals('reply', $this->commandOutput->blockingMode()->getCommandReply()); + public function testCloseThenPublisherCallUnbind() { + $this->publisher->expects($this->once())->method('unbind'); + $this->output->close(); } - public function testClose() { - $this->senderMock->expects($this->once())->method('disconnect'); - $this->commandOutput->close(); - } } From c31c27949ef8d1a5f6df6e8fc935c221a0c2c89c Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Thu, 13 Oct 2016 09:46:55 +0200 Subject: [PATCH 079/133] added correlation_id --- .../Component/Worker/Command/CommandReply.php | 42 +++++++++++++++---- .../Worker/Command/CommandReplyTest.php | 11 ++--- 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/src/SAREhub/Component/Worker/Command/CommandReply.php b/src/SAREhub/Component/Worker/Command/CommandReply.php index cb71cc9..2779f2e 100644 --- a/src/SAREhub/Component/Worker/Command/CommandReply.php +++ b/src/SAREhub/Component/Worker/Command/CommandReply.php @@ -7,6 +7,8 @@ class CommandReply implements \JsonSerializable { const SUCCESS_STATUS = 'success'; const ERROR_STATUS = 'error'; + private $correlationId; + /** * @var string */ @@ -22,12 +24,21 @@ class CommandReply implements \JsonSerializable { */ private $data; - protected function __construct($status, $message, $data) { + /** + * CommandReply constructor. + * @param $correlationId + * @param $status + * @param $message + * @param $data + */ + protected function __construct($correlationId, $status, $message, $data) { + $this->correlationId = $correlationId; $this->status = $status; $this->message = $message; $this->data = $data; } + /** * @param string $reply * @return CommandReply @@ -41,37 +52,51 @@ public static function createFromJson($reply) { * @return CommandReply */ public static function createFromArray(array $reply) { - return new self($reply['status'], $reply['message'], $reply['data']); + return new self( + $reply['correlation_id'], + $reply['status'], + $reply['message'], + $reply['data'] + ); } /** + * @param $correlationId * @param string $message * @param mixed $data * @return CommandReply */ - public static function success($message, $data = null) { - return self::reply(self::SUCCESS_STATUS, $message, $data); + public static function success($correlationId, $message, $data = null) { + return self::reply($correlationId, self::SUCCESS_STATUS, $message, $data); } /** + * @param $correlationId * @param string $message * @param mixed $data * @return CommandReply */ - public static function error($message, $data = null) { - return self::reply(self::ERROR_STATUS, $message, $data); + public static function error($correlationId, $message, $data = null) { + return self::reply($correlationId, self::ERROR_STATUS, $message, $data); } /** + * @param string $correlationId * @param string $status * @param string $message * @param mixed $data * @return CommandReply */ - public static function reply($status, $message, $data = null) { - return new self($status, $message, $data); + public static function reply($correlationId, $status, $message, $data = null) { + return new self($correlationId, $status, $message, $data); } + /** + * @return string + */ + public function getCorrelationId() { + return $this->correlationId; + } /** * @return string */ @@ -109,6 +134,7 @@ public function getData() { public function jsonSerialize() { return [ + 'correlation_id' => $this->getCorrelationId(), 'status' => $this->getStatus(), 'message' => $this->getMessage(), 'data' => $this->getData() diff --git a/tests/unit/SAREhub/Component/Worker/Command/CommandReplyTest.php b/tests/unit/SAREhub/Component/Worker/Command/CommandReplyTest.php index 11789bc..ca3d1f3 100644 --- a/tests/unit/SAREhub/Component/Worker/Command/CommandReplyTest.php +++ b/tests/unit/SAREhub/Component/Worker/Command/CommandReplyTest.php @@ -7,33 +7,34 @@ class CommandReplyTest extends TestCase { public function testReply() { - $reply = CommandReply::reply('s', 'm', 'd'); + $reply = CommandReply::reply('id', 's', 'm', 'd'); + $this->assertEquals('id', $reply->getCorrelationId()); $this->assertEquals('s', $reply->getStatus()); $this->assertEquals('m', $reply->getMessage()); $this->assertEquals('d', $reply->getData()); } public function testSuccess() { - $reply = CommandReply::success('m', 'd'); + $reply = CommandReply::success('id', 'm', 'd'); $this->assertEquals(CommandReply::SUCCESS_STATUS, $reply->getStatus()); $this->assertEquals('m', $reply->getMessage()); $this->assertEquals('d', $reply->getData()); } public function testError() { - $reply = CommandReply::error('m', 'd'); + $reply = CommandReply::error('id', 'm', 'd'); $this->assertEquals(CommandReply::ERROR_STATUS, $reply->getStatus()); $this->assertEquals('m', $reply->getMessage()); $this->assertEquals('d', $reply->getData()); } public function testIsSuccess() { - $reply = CommandReply::success('m', 'd'); + $reply = CommandReply::success('id', 'm', 'd'); $this->assertTrue($reply->isSuccess()); } public function testIsError() { - $reply = CommandReply::error('m', 'd'); + $reply = CommandReply::error('id', 'm', 'd'); $this->assertTrue($reply->isError()); } From 9028896956f0094a231ab490ed96b61c36657c94 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Thu, 13 Oct 2016 09:50:26 +0200 Subject: [PATCH 080/133] refactored --- .../Worker/Command/CommandReplyOutput.php | 4 +- .../Worker/Command/ZmqCommandReplyOutput.php | 16 ++----- .../Command/ZmqCommandOutputFactoryTest.php | 46 ------------------- .../Command/ZmqCommandReplyOutputTest.php | 11 ++--- 4 files changed, 10 insertions(+), 67 deletions(-) delete mode 100644 tests/unit/SAREhub/Component/Worker/Command/ZmqCommandOutputFactoryTest.php diff --git a/src/SAREhub/Component/Worker/Command/CommandReplyOutput.php b/src/SAREhub/Component/Worker/Command/CommandReplyOutput.php index c37c327..135a675 100644 --- a/src/SAREhub/Component/Worker/Command/CommandReplyOutput.php +++ b/src/SAREhub/Component/Worker/Command/CommandReplyOutput.php @@ -6,12 +6,12 @@ interface CommandReplyOutput { /** * Sends reply for command - * @param Command $command + * @param string $topic * @param CommandReply $reply * @param bool $wait * @return */ - public function send(Command $command, CommandReply $reply, $wait = false); + public function send($topic, CommandReply $reply, $wait = false); /** * Will close command input diff --git a/src/SAREhub/Component/Worker/Command/ZmqCommandReplyOutput.php b/src/SAREhub/Component/Worker/Command/ZmqCommandReplyOutput.php index 0bc1485..245a789 100644 --- a/src/SAREhub/Component/Worker/Command/ZmqCommandReplyOutput.php +++ b/src/SAREhub/Component/Worker/Command/ZmqCommandReplyOutput.php @@ -7,23 +7,17 @@ class ZmqCommandReplyOutput implements CommandReplyOutput { - /** - * @var string - */ - private $publishTopic = ''; - /** * @var Publisher */ private $publisher; - public function __construct(Publisher $publisher, $publishTopic = '') { + public function __construct(Publisher $publisher) { $this->publisher = $publisher; - $this->publishTopic = $publishTopic; } - public function send(Command $command, CommandReply $reply, $wait = false) { - $this->getPublisher()->publish($this->getPublishTopic(), $reply->toJson(), $wait); + public function send($topic, CommandReply $reply, $wait = false) { + $this->getPublisher()->publish($topic, $reply->toJson(), $wait); } public function close() { @@ -33,8 +27,4 @@ public function close() { public function getPublisher() { return $this->publisher; } - - public function getPublishTopic() { - return $this->publishTopic; - } } \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandOutputFactoryTest.php b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandOutputFactoryTest.php deleted file mode 100644 index 9ce48a8..0000000 --- a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandOutputFactoryTest.php +++ /dev/null @@ -1,46 +0,0 @@ -commandFormatMock = $this->createMock(CommandFormat::class); - $this->senderMock = $this->createMock(RequestSender::class); - $this->senderFactoryMock = $this->getMockBuilder(stdClass::class)->setMethods(['__invoke'])->getMock(); - $this->senderFactoryMock->method('__invoke')->willReturn($this->senderMock); - $this->factory = new ZmqCommandOutputFactory($this->senderFactoryMock, $this->commandFormatMock); - } - - public function testCreateThenCreateCallSenderFactory() { - $workerId = 'worker1'; - $this->senderFactoryMock->expects($this->once())->method('__invoke') - ->with($workerId)->willReturn($this->senderMock); - $this->factory->create($workerId); - } - - public function testCreateThenReturnOutput() { - $this->assertInstanceOf(ZmqCommandOutput::class, $this->factory->create('workerId')); - } - - public function testCreateThenSenderSets() { - $output = $this->factory->create('worker1'); - $this->assertSame($this->senderMock, $output->getSender()); - } - - public function testCreateThenCommandFormatSets() { - $output = $this->factory->create('worker1'); - $this->assertSame($this->commandFormatMock, $output->getCommandFormat()); - } -} diff --git a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandReplyOutputTest.php b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandReplyOutputTest.php index d2608a4..9ad44e5 100644 --- a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandReplyOutputTest.php +++ b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandReplyOutputTest.php @@ -2,7 +2,6 @@ use PHPUnit\Framework\TestCase; use SAREhub\Commons\Zmq\PublishSubscribe\Publisher; -use SAREhub\Component\Worker\Command\BasicCommand; use SAREhub\Component\Worker\Command\CommandReply; use SAREhub\Component\Worker\Command\ZmqCommandReplyOutput; @@ -23,21 +22,21 @@ class ZmqCommandReplyOutputTest extends TestCase { protected function setUp() { parent::setUp(); $this->publisher = $this->createMock(Publisher::class); - $this->output = new ZmqCommandReplyOutput($this->publisher, $this->topic); + $this->output = new ZmqCommandReplyOutput($this->publisher); } public function testSendThenPublisherPublish() { - $reply = CommandReply::success("reply"); + $reply = CommandReply::success("id", "reply"); $this->publisher->expects($this->once())->method('publish') ->with($this->topic, $reply->toJson(), false); - $this->output->send(new BasicCommand("name"), $reply); + $this->output->send($this->topic, $reply); } public function testSendWhenWaitThenPublisherPublishWithWait() { - $reply = CommandReply::success("reply"); + $reply = CommandReply::success("id", "reply"); $this->publisher->expects($this->once())->method('publish') ->with($this->topic, $reply->toJson(), true); - $this->output->send(new BasicCommand("name"), $reply, true); + $this->output->send($this->topic, $reply, true); } public function testClose() { From f287555a1539c4682d11413945cbb497198fa413 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Thu, 13 Oct 2016 10:28:27 +0200 Subject: [PATCH 081/133] aded CommandReplyInput --- .../Worker/Command/CommandReplyInput.php | 15 ++++++ .../Worker/Command/ZmqCommandReplyInput.php | 30 ++++++++++++ .../Command/ZmqCommandReplyInputTest.php | 48 +++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 src/SAREhub/Component/Worker/Command/CommandReplyInput.php create mode 100644 src/SAREhub/Component/Worker/Command/ZmqCommandReplyInput.php create mode 100644 tests/unit/SAREhub/Component/Worker/Command/ZmqCommandReplyInputTest.php diff --git a/src/SAREhub/Component/Worker/Command/CommandReplyInput.php b/src/SAREhub/Component/Worker/Command/CommandReplyInput.php new file mode 100644 index 0000000..4c68f29 --- /dev/null +++ b/src/SAREhub/Component/Worker/Command/CommandReplyInput.php @@ -0,0 +1,15 @@ +subscriber = $subscriber; + } + + /** + * @param bool $wait + * @return null|CommandReply + */ + public function getNext($wait = false) { + $replyData = $this->subscriber->receive($wait); + return ($replyData) ? CommandReply::createFromJson($replyData['body']) : null; + } + + public function close() { + $this->subscriber->disconnect(); + } +} \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandReplyInputTest.php b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandReplyInputTest.php new file mode 100644 index 0000000..1eb4d4b --- /dev/null +++ b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandReplyInputTest.php @@ -0,0 +1,48 @@ +subscriber = $this->createMock(Subscriber::class); + $this->input = new ZmqCommandReplyInput($this->subscriber); + } + + public function testGetNextThenSubscriberCallReceive() { + $this->subscriber->expects($this->once())->method('receive')->with(false); + $this->input->getNext(); + } + + public function testGetNextWhenWaitThenSubscriberCallReceiveWithWait() { + $this->subscriber->expects($this->once())->method('receive')->with(true); + $this->input->getNext(true); + } + + public function testGetNextWhenNotMessageThenReturnNull() { + $this->subscriber->method('receive')->willReturn(null); + $this->assertNull($this->input->getNext()); + } + + public function testGetNextWhenMessageThenReturnReplyInstance() { + $this->subscriber->method('receive')->willReturn([ + 'topic' => 'topic1', + 'body' => CommandReply::success('1', 'test')->toJson() + ]); + $this->assertInstanceOf(CommandReply::class, $this->input->getNext()); + } + + public function testCloseThenSubscriberDisconnect() { + $this->subscriber->expects($this->once())->method('disconnect'); + $this->input->close(); + } + +} From 74b05dfb5a7541937151bb5905094aab9cb9af17 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Thu, 13 Oct 2016 11:06:31 +0200 Subject: [PATCH 082/133] moved topic to constructor --- .../Worker/Command/CommandReplyOutput.php | 3 +-- .../Worker/Command/ZmqCommandReplyOutput.php | 19 ++++++++++++++++--- .../Command/ZmqCommandReplyOutputTest.php | 14 +++++++------- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/SAREhub/Component/Worker/Command/CommandReplyOutput.php b/src/SAREhub/Component/Worker/Command/CommandReplyOutput.php index 135a675..5b1aa94 100644 --- a/src/SAREhub/Component/Worker/Command/CommandReplyOutput.php +++ b/src/SAREhub/Component/Worker/Command/CommandReplyOutput.php @@ -6,12 +6,11 @@ interface CommandReplyOutput { /** * Sends reply for command - * @param string $topic * @param CommandReply $reply * @param bool $wait * @return */ - public function send($topic, CommandReply $reply, $wait = false); + public function send(CommandReply $reply, $wait = false); /** * Will close command input diff --git a/src/SAREhub/Component/Worker/Command/ZmqCommandReplyOutput.php b/src/SAREhub/Component/Worker/Command/ZmqCommandReplyOutput.php index 245a789..ade6c24 100644 --- a/src/SAREhub/Component/Worker/Command/ZmqCommandReplyOutput.php +++ b/src/SAREhub/Component/Worker/Command/ZmqCommandReplyOutput.php @@ -12,19 +12,32 @@ class ZmqCommandReplyOutput implements CommandReplyOutput { */ private $publisher; - public function __construct(Publisher $publisher) { + private $publishTopic; + + public function __construct(Publisher $publisher, $publishTopic) { $this->publisher = $publisher; + $this->publishTopic = $publishTopic; } - public function send($topic, CommandReply $reply, $wait = false) { - $this->getPublisher()->publish($topic, $reply->toJson(), $wait); + public function send(CommandReply $reply, $wait = false) { + $this->getPublisher()->publish($this->getPublishTopic(), $reply->toJson(), $wait); } public function close() { $this->publisher->unbind(); } + /** + * @return Publisher + */ public function getPublisher() { return $this->publisher; } + + /** + * @return string + */ + public function getPublishTopic() { + return $this->publishTopic; + } } \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandReplyOutputTest.php b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandReplyOutputTest.php index 9ad44e5..9474365 100644 --- a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandReplyOutputTest.php +++ b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandReplyOutputTest.php @@ -18,25 +18,25 @@ class ZmqCommandReplyOutputTest extends TestCase { private $output; private $topic = 'reply'; + private $reply; protected function setUp() { parent::setUp(); $this->publisher = $this->createMock(Publisher::class); - $this->output = new ZmqCommandReplyOutput($this->publisher); + $this->output = new ZmqCommandReplyOutput($this->publisher, $this->topic); + $this->reply = CommandReply::success("id", "reply"); } public function testSendThenPublisherPublish() { - $reply = CommandReply::success("id", "reply"); $this->publisher->expects($this->once())->method('publish') - ->with($this->topic, $reply->toJson(), false); - $this->output->send($this->topic, $reply); + ->with($this->topic, $this->reply->toJson(), false); + $this->output->send($this->reply); } public function testSendWhenWaitThenPublisherPublishWithWait() { - $reply = CommandReply::success("id", "reply"); $this->publisher->expects($this->once())->method('publish') - ->with($this->topic, $reply->toJson(), true); - $this->output->send($this->topic, $reply, true); + ->with($this->topic, $this->reply->toJson(), true); + $this->output->send($this->reply, true); } public function testClose() { From ded89908f49f5023f138d186f2cbb4796c7041fc Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Thu, 13 Oct 2016 11:38:31 +0200 Subject: [PATCH 083/133] fixes for new code --- src/SAREhub/Component/Worker/WorkerRunner.php | 151 ++++++++++++++++-- .../Component/Worker/WorkerRunnerTest.php | 62 ++++--- 2 files changed, 177 insertions(+), 36 deletions(-) diff --git a/src/SAREhub/Component/Worker/WorkerRunner.php b/src/SAREhub/Component/Worker/WorkerRunner.php index d7a298f..a9a7ef3 100644 --- a/src/SAREhub/Component/Worker/WorkerRunner.php +++ b/src/SAREhub/Component/Worker/WorkerRunner.php @@ -2,12 +2,20 @@ namespace SAREhub\Component\Worker; +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerInterface; +use Psr\Log\NullLogger; +use SAREhub\Component\Worker\Command\Command; use SAREhub\Component\Worker\Command\CommandInput; +use SAREhub\Component\Worker\Command\CommandReply; +use SAREhub\Component\Worker\Command\CommandReplyOutput; /** * Helper class for run worker. */ -class WorkerRunner { +class WorkerRunner implements LoggerAwareInterface { + + private $logger; /** * @var Worker @@ -19,40 +27,133 @@ class WorkerRunner { */ private $commandInput; - protected function __construct(Worker $worker, CommandInput $commandInput) { + private $commandReplyOutput; + + protected function __construct() { + $this->logger = new NullLogger(); + } + + /** + * @return WorkerRunner + */ + public static function newInstance() { + return new self(); + } + + /** + * @param Worker $worker + * @return $this + */ + public function withWorker(Worker $worker) { $this->worker = $worker; - $this->commandInput = $commandInput; + return $this; + } + + /** + * @param CommandInput $input + * @return $this + */ + public function withCommandInput(CommandInput $input) { + $this->commandInput = $input; + return $this; } - public static function newWithWorkerAndCommandInput(Worker $worker, CommandInput $commandInput) { - return new self($worker, $commandInput); + /** + * @param CommandReplyOutput $output + * @return $this + */ + public function withCommandReplyOutput(CommandReplyOutput $output) { + $this->commandReplyOutput = $output; + return $this; } + /** + * Starts worker + */ public function start() { - $this->getWorker()->start(); + try { + $this->getWorker()->start(); + } catch (\Exception $e) { + $this->getLogger()->error($e); + } } + /** + * @return bool + */ public function tick() { - $this->checkCommand(); - if ($this->getWorker()->isStarted()) { + try { + $this->checkCommand(); $this->getWorker()->tick(); - return true; + } catch (\Exception $e) { + $this->getLogger()->error($e); } - - return false; } public function stop() { - $this->getWorker()->stop(); + try { + $this->getWorker()->stop(); + $this->getCommandInput()->close(); + $this->getCommandReplyOutput()->close(); + } catch (\Exception $e) { + $this->getLogger()->error($e); + } } - protected function checkCommand() { - if ($command = $this->getCommandInput()->getNextCommand()) { - $reply = $this->getWorker()->processCommand($command); - $this->getCommandInput()->sendCommandReply($reply); + private function checkCommand() { + if ($command = $this->getCommandInput()->getNext()) { + $reply = $this->processCommand($command); + $this->getLogger()->info('sending reply', ['reply' => $reply]); + $this->getCommandReplyOutput()->send($reply, true); } } + + private function processCommand(Command $command) { + $this->getLogger()->info('process command', ['command' => (string)$command]); + try { + $reply = $this->onCommand($command); + if ($reply === null) { + throw new \LogicException('empty reply'); + } + } catch (\Exception $e) { + $reply = $this->onProcessCommandException($command, $e); + } + + return $reply; + } + + private function onCommand(Command $command) { + switch ($command->getName()) { + case WorkerCommands::STOP: + return $this->onStopCommand($command); + break; + default: + return $this->worker->processCommand($command); + } + } + + private function onStopCommand(Command $command) { + $this->getWorker()->stop(); + return CommandReply::success($command->getCorrelationId(), 'stopped'); + } + + private function onProcessCommandException(Command $command, \Exception $e) { + $this->getLogger()->error($e); + return CommandReply::error( + $command->getCorrelationId(), + 'exception when execute command', [ + 'exceptionMessage' => $e->getMessage() + ]); + } + + /** + * @return bool + */ + public function isRunning() { + return !$this->getWorker()->isStopped(); + } + /** * @return Worker */ @@ -66,4 +167,22 @@ public function getWorker() { public function getCommandInput() { return $this->commandInput; } + + /** + * @return CommandReplyOutput + */ + public function getCommandReplyOutput() { + return $this->commandReplyOutput; + } + + /** + * @return LoggerInterface + */ + public function getLogger() { + return $this->logger; + } + + public function setLogger(LoggerInterface $logger) { + $this->logger = $logger; + } } \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php b/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php index b51a63e..916cbc9 100644 --- a/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php +++ b/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php @@ -3,6 +3,8 @@ use PHPUnit\Framework\TestCase; use SAREhub\Component\Worker\Command\BasicCommand; use SAREhub\Component\Worker\Command\CommandInput; +use SAREhub\Component\Worker\Command\CommandReply; +use SAREhub\Component\Worker\Command\CommandReplyOutput; use SAREhub\Component\Worker\WorkerRunner; class WorkerRunnerTest extends TestCase { @@ -13,53 +15,73 @@ class WorkerRunnerTest extends TestCase { /** @var PHPUnit_Framework_MockObject_MockObject */ private $commandInputMock; + /** @var PHPUnit_Framework_MockObject_MockObject */ + private $commandReplyOutputMock; + /** @var WorkerRunner */ private $workerRunner; - protected function setUp() { - $this->workerMock = $this->createMock(SAREhub\Component\Worker\Worker::class); - $this->commandInputMock = $this->createMock(CommandInput::class); - $this->workerRunner = WorkerRunner::newWithWorkerAndCommandInput($this->workerMock, $this->commandInputMock); - } - public function testStart() { $this->workerMock->expects($this->once())->method('start'); $this->workerRunner->start(); } public function testTick() { - $this->workerMock->method('isStarted')->willReturn('true'); $this->workerMock->expects($this->once())->method('tick'); $this->workerRunner->tick(); } public function testStop() { $this->workerMock->expects($this->once())->method('stop'); + $this->commandInputMock->expects($this->once())->method('close'); + $this->commandReplyOutputMock->expects($this->once())->method('close'); $this->workerRunner->stop(); } - public function testCheckCommandWhenCommandWasReceive() { - $commmand = new BasicCommand('test'); - $commandReply = 'reply'; - $this->commandInputMock->expects($this->once())->method('getNextCommand')->willReturn($commmand); - $this->commandInputMock->expects($this->once())->method('sendCommandReply')->with($commandReply); + public function testTickWhenCommandThenWorkerProcessCommand() { + $command = new BasicCommand('1', 'test'); + $this->commandInputMock->expects($this->once())->method('getNext')->willReturn($command); $this->workerMock->expects($this->once())->method('processCommand') - ->with($this->identicalTo($commmand))->willReturn($commandReply); + ->with($this->identicalTo($command)); $this->workerRunner->tick(); } - public function testCheckCommandWhenNoCommand() { - $this->commandInputMock->expects($this->once())->method('getNextCommand')->willReturn(null); + public function testTickWhenNoCommandThenWorkerNotProcessCommand() { + $this->commandInputMock->expects($this->once())->method('getNext')->willReturn(null); $this->workerMock->expects($this->never())->method('processCommand'); $this->workerRunner->tick(); } - public function testCheckCommandWhenWorkerIsStopped() { - $this->commandInputMock->expects($this->once())->method('getNextCommand')->willReturn(new BasicCommand('name')); - $this->commandInputMock->expects($this->once())->method('sendCommandReply'); - $this->workerMock->expects($this->once())->method('processCommand'); - + public function testTickWhenProcessCommandException() { + $command = new BasicCommand('1', 'c'); + $this->commandInputMock->expects($this->once())->method('getNext')->willReturn($command); + $this->workerMock->method('processCommand')->willThrowException(new \Exception('m')); + $this->commandReplyOutputMock->expects($this->once())->method('send') + ->with($this->callback(function (CommandReply $reply) { + return $reply->getMessage() === 'exception when execute command'; + })); $this->workerRunner->tick(); } + + public function testTickWhenProcessCommandEmptyReply() { + $command = new BasicCommand('1', 'c'); + $this->commandInputMock->expects($this->once())->method('getNext')->willReturn($command); + $this->workerMock->method('processCommand')->willReturn(null); + $this->commandReplyOutputMock->expects($this->once())->method('send') + ->with($this->callback(function (CommandReply $reply) { + return $reply->getMessage() === 'exception when execute command'; + })); + $this->workerRunner->tick(); + } + + protected function setUp() { + $this->workerMock = $this->createMock(SAREhub\Component\Worker\Worker::class); + $this->commandInputMock = $this->createMock(CommandInput::class); + $this->commandReplyOutputMock = $this->createMock(CommandReplyOutput::class); + $this->workerRunner = WorkerRunner::newInstance() + ->withWorker($this->workerMock) + ->withCommandInput($this->commandInputMock) + ->withCommandReplyOutput($this->commandReplyOutputMock); + } } From a5e30321e6cdf5b5bae94bf91657d2d72b19335a Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Thu, 13 Oct 2016 11:39:11 +0200 Subject: [PATCH 084/133] fixes for new code --- src/SAREhub/Component/Worker/BasicWorker.php | 1 - .../SAREhub/Component/Worker/BasicWorkerTest.php | 14 ++++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/SAREhub/Component/Worker/BasicWorker.php b/src/SAREhub/Component/Worker/BasicWorker.php index b7b1e04..f69a306 100644 --- a/src/SAREhub/Component/Worker/BasicWorker.php +++ b/src/SAREhub/Component/Worker/BasicWorker.php @@ -27,7 +27,6 @@ public function processCommand(Command $command) { /** * Contains custom command processing logic. - * * @param Command $command * @throws WorkerException When something was wrong. */ diff --git a/tests/unit/SAREhub/Component/Worker/BasicWorkerTest.php b/tests/unit/SAREhub/Component/Worker/BasicWorkerTest.php index 081c5e1..09a1199 100644 --- a/tests/unit/SAREhub/Component/Worker/BasicWorkerTest.php +++ b/tests/unit/SAREhub/Component/Worker/BasicWorkerTest.php @@ -33,28 +33,30 @@ class BasicWorkerTest extends TestCase { */ private $worker; + private $command; + protected function setUp() { parent::setUp(); $this->worker = $this->createPartialMock(TestBasicWorker::class, ['doCommand']); + $this->command = new BasicCommand('1', 'test'); } public function testProcessCommandThenDoCommand() { $spy = $this->getMethodSpy('doCommand'); - $this->worker->processCommand(new BasicCommand('test')); + $this->worker->processCommand($this->command); $this->assertEquals(1, $spy->getInvocationCount()); } public function testProcessCommandThenDoCommandWithCommandParameter() { $spy = $this->getMethodSpy('doCommand'); - $command = new BasicCommand('test'); - $this->worker->processCommand($command); - $this->assertSame($command, $spy->getInvocations()[0]->parameters[0]); + $this->worker->processCommand($this->command); + $this->assertSame($this->command, $spy->getInvocations()[0]->parameters[0]); } public function testProcessCommandThenReturnReply() { - $expectedReply = CommandReply::success('r'); + $expectedReply = CommandReply::success('1', 'r'); $this->worker->expects($this->once())->method('doCommand')->willReturn($expectedReply); - $this->assertSame($expectedReply, $this->worker->processCommand(new BasicCommand('test'))); + $this->assertSame($expectedReply, $this->worker->processCommand($this->command)); } private function getMethodSpy($method) { From 9befef04017083b4cbbefcc8a5b97107655df2f5 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Thu, 13 Oct 2016 14:09:01 +0200 Subject: [PATCH 085/133] added WorkerCommandRequest --- .../Worker/Manager/WorkerCommandRequest.php | 120 ++++++++++++++++++ .../Manager/WorkerCommandRequestTest.php | 29 +++++ 2 files changed, 149 insertions(+) create mode 100644 src/SAREhub/Component/Worker/Manager/WorkerCommandRequest.php create mode 100644 tests/unit/SAREhub/Component/Worker/Manager/WorkerCommandRequestTest.php diff --git a/src/SAREhub/Component/Worker/Manager/WorkerCommandRequest.php b/src/SAREhub/Component/Worker/Manager/WorkerCommandRequest.php new file mode 100644 index 0000000..c387da1 --- /dev/null +++ b/src/SAREhub/Component/Worker/Manager/WorkerCommandRequest.php @@ -0,0 +1,120 @@ +workerId = $id; + return $this; + } + + public function withCommand(Command $command) { + $this->command = $command; + return $this; + } + + public function withReplyTimeout($timeout) { + $this->replyTimeout = $timeout; + return $this; + } + + public function withReplyCallback(callable $callback) { + $this->replyCallback = $callback; + return $this; + } + + public function markAsSent($now) { + $this->sentTime = $now; + } + + /** + * @return bool + */ + public function isSent() { + return $this->getSentTime() > 0; + } + + /** + * @param $now + * @return bool + */ + public function isReplyTimeout($now) { + return $this->isSent() && $now >= ($this->getSentTime() + $this->getReplyTimeout()); + } + + /** + * @return string + */ + public function getWorkerId() { + return $this->workerId; + } + + /** + * @return Command + */ + public function getCommand() { + return $this->command; + } + + /** + * @return int + */ + public function getSentTime() { + return $this->sentTime; + } + + /** + * @return int + */ + public function getReplyTimeout() { + return $this->replyTimeout; + } + + /** + * @return callable + */ + public function getReplyCallback() { + return $this->replyCallback; + } + +} \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Manager/WorkerCommandRequestTest.php b/tests/unit/SAREhub/Component/Worker/Manager/WorkerCommandRequestTest.php new file mode 100644 index 0000000..2f28599 --- /dev/null +++ b/tests/unit/SAREhub/Component/Worker/Manager/WorkerCommandRequestTest.php @@ -0,0 +1,29 @@ +assertFalse(WorkerCommandRequest::newInstance()->isSent()); + } + + public function testMarkAsSentThenIsSentReturnTrue() { + $request = WorkerCommandRequest::newInstance(); + $request->markAsSent(time()); + $this->assertTrue($request->isSent()); + } + + public function testIsReplyTimeoutWhenNotSentThenReturnFalse() { + $request = WorkerCommandRequest::newInstance(); + $this->assertFalse($request->isReplyTimeout(time())); + } + + public function testIsReplyTimeoutWhenSentAndNotTimeoutThenReturnFalse() { + $request = WorkerCommandRequest::newInstance(); + $now = time(); + $request->markAsSent($now); + $this->assertFalse($request->isReplyTimeout($now)); + } +} From aa9a38578143dd7b4af5f42fb06da04dab0272a3 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Thu, 13 Oct 2016 14:10:24 +0200 Subject: [PATCH 086/133] fixes --- src/SAREhub/Component/Worker/Manager/WorkerProcess.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/SAREhub/Component/Worker/Manager/WorkerProcess.php b/src/SAREhub/Component/Worker/Manager/WorkerProcess.php index 569e4ff..3dccc44 100644 --- a/src/SAREhub/Component/Worker/Manager/WorkerProcess.php +++ b/src/SAREhub/Component/Worker/Manager/WorkerProcess.php @@ -21,7 +21,6 @@ public function __construct($id, Process $process) { $this->process = $process; } - /** * Starts worker process. */ @@ -36,10 +35,19 @@ public function kill() { $this->process->stop(); } + /** + * @return bool + */ public function isRunning() { return $this->process->isRunning(); } + /** + * @return int|null + */ + public function getPid() { + return $this->process->getPid(); + } /** * @return string */ From 9c444404727d8e570f186c9c2fb240aeb254af5b Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Thu, 13 Oct 2016 15:59:48 +0200 Subject: [PATCH 087/133] refactored --- .../Worker/Manager/WorkerCommandService.php | 157 ++++++++++-------- .../Manager/WorkerCommandServiceTest.php | 153 ++++++++++------- 2 files changed, 183 insertions(+), 127 deletions(-) diff --git a/src/SAREhub/Component/Worker/Manager/WorkerCommandService.php b/src/SAREhub/Component/Worker/Manager/WorkerCommandService.php index 442924b..785c960 100644 --- a/src/SAREhub/Component/Worker/Manager/WorkerCommandService.php +++ b/src/SAREhub/Component/Worker/Manager/WorkerCommandService.php @@ -2,85 +2,88 @@ namespace SAREhub\Component\Worker\Manager; -use Psr\Log\LoggerInterface; -use Psr\Log\NullLogger; use SAREhub\Commons\Misc\TimeProvider; -use SAREhub\Component\Worker\Command\Command; use SAREhub\Component\Worker\Command\CommandOutput; -use SAREhub\Component\Worker\Command\CommandOutputFactory; use SAREhub\Component\Worker\Command\CommandReply; +use SAREhub\Component\Worker\Command\CommandReplyInput; use SAREhub\Component\Worker\Service\ServiceSupport; class WorkerCommandService extends ServiceSupport { - const DEFAULT_COMMAND_REPLY_TIMEOUT = 30; + /** + * @var CommandOutput + */ + private $commandOutput; /** - * @var LoggerInterface + * @var CommandReplyInput */ - private $logger; + private $commandReplyInput; /** - * @var CommandOutputFactory + * @var WorkerCommandRequest[] */ - private $outputFactory; + private $pendingRequests = []; + + + protected function __construct() { + } /** - * @var CommandOutput[] + * @return WorkerCommandService */ - private $outputList = []; + public static function newInstance() { + return new self(); + } - public function __construct(CommandOutputFactory $factory) { - $this->outputFactory = $factory; - $this->logger = new NullLogger(); + /** + * @param CommandOutput $output + * @return $this + */ + public function withCommandOutput(CommandOutput $output) { + $this->commandOutput = $output; + return $this; } /** - * @param string $id + * @param CommandReplyInput $input + * @return $this */ - public function register($id) { - if (!$this->has($id)) { - $this->outputList[$id] = $this->outputFactory->create($id); + public function withCommandReplyInput(CommandReplyInput $input) { + $this->commandReplyInput = $input; + return $this; + } + + public function process(WorkerCommandRequest $request) { + $this->getLogger()->info('sending command request', ['request' => $request]); + try { + $this->commandOutput->send($request->getWorkerId(), $request->getCommand(), false); + $request->markAsSent(TimeProvider::get()->now()); + $this->pendingRequests[] = $request; + } catch (\Exception $e) { + $this->onRequestException($request, $e); } } /** - * @param string $id + * @return WorkerCommandRequest[] */ - public function unregister($id) { - if ($output = $this->get($id)) { - $output->close(); - unset($this->outputList[$id]); - } + public function getPendingRequests() { + return $this->pendingRequests; } /** - * @param string $id - * @param Command $command - * @param int $replyTimeout - * @return CommandReply + * @return CommandOutput */ - public function sendCommand($id, Command $command, $replyTimeout = self::DEFAULT_COMMAND_REPLY_TIMEOUT) { - if ($output = $this->get($id)) { - try { - $output->sendCommand($command); - $timeoutTime = TimeProvider::get()->now() + $replyTimeout; - while (true) { - if ($reply = $output->getCommandReply()) { - return CommandReply::createFromJson($reply); - } - - if (TimeProvider::get()->now() >= $timeoutTime) { - return CommandReply::error('reply timeout'); - } - } - } catch (\Exception $e) { - $this->logger->error($e); - return CommandReply::error($e->getMessage()); - } - } - - return CommandReply::error('worker not exists', $id); + public function getCommandOutput() { + return $this->commandOutput; + } + + /** + * @return CommandReplyInput + */ + public function getCommandReplyInput() { + return $this->commandReplyInput; } protected function doStart() { @@ -88,33 +91,57 @@ protected function doStart() { } protected function doTick() { + if ($reply = $this->getCommandReplyInput()->getNext()) { + $this->getLogger()->info('got reply', ['reply' => $reply]); + if ($request = $this->getCorrelatedPendingRequest($reply)) { + $this->getLogger()->info('exists correlated command', + ['request' => $request], + ['reply' => $reply] + ); + ($request->getReplyCallback())($request, $reply); + } + $this->getLogger()->info('not exists correlated command for reply', ['reply' => $reply]); + } + $this->checkReplyTimeout(); } protected function doStop() { - foreach ($this->outputList as $id => $output) { - $this->unregister($id); - } } - - /** - * @param string $id - * @return null|CommandOutput - */ - protected function get($id) { - return $this->has($id) ? $this->outputList[$id] : null; + private function onRequestException(WorkerCommandRequest $request, \Exception $exception) { + $this->getLogger()->error($exception, ['request' => $request]); + $reply = CommandReply::error( + $request->getCommand()->getCorrelationId(), + 'exception when send command', + ['exceptionMessage' => $exception->getMessage()] + ); + ($request->getReplyCallback())($request, $reply); } /** - * @param string $id - * @return bool + * @param CommandReply $reply + * @return null|WorkerCommandRequest */ - public function has($id) { - return isset($this->outputList[$id]); + private function getCorrelatedPendingRequest(CommandReply $reply) { + foreach ($this->getPendingRequests() as $request) { + if ($reply->getCorrelationId() === $request->getCommand()->getCorrelationId()) { + return $request; + } + } + + return null; } - public function setLogger(LoggerInterface $logger) { - $this->logger = $logger; + private function checkReplyTimeout() { + foreach ($this->getPendingRequests() as $request) { + if ($request->isReplyTimeout(TimeProvider::get()->now())) { + $reply = CommandReply::error( + $request->getCommand()->getCorrelationId(), + 'reply timeout' + ); + ($request->getReplyCallback())($request, $reply); + } + } } } \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Manager/WorkerCommandServiceTest.php b/tests/unit/SAREhub/Component/Worker/Manager/WorkerCommandServiceTest.php index c4ceec1..e1ff469 100644 --- a/tests/unit/SAREhub/Component/Worker/Manager/WorkerCommandServiceTest.php +++ b/tests/unit/SAREhub/Component/Worker/Manager/WorkerCommandServiceTest.php @@ -1,12 +1,12 @@ factoryMock = $this->createMock(CommandOutputFactory::class); $this->outputMock = $this->createMock(CommandOutput::class); - $this->factoryMock->method('create')->willReturn($this->outputMock); - $this->service = new WorkerCommandService($this->factoryMock); + $this->inputMock = $this->createMock(CommandReplyInput::class); + $this->service = WorkerCommandService::newInstance() + ->withCommandOutput($this->outputMock) + ->withCommandReplyInput($this->inputMock); + + $this->service->start(); + + $this->request = WorkerCommandRequest::newInstance() + ->withWorkerId('worker1') + ->withCommand(new BasicCommand('1', 'c')) + ->withReplyCallback($this->createPartialMock(stdClass::class, ['__invoke'])); } - public function testRegisterWhenNotExists() { - $this->factoryMock->expects($this->once())->method('create') - ->with('id')->willReturn($this->outputMock); - $this->service->register('id'); - $this->assertTrue($this->service->has('id')); + protected function tearDown() { + parent::tearDown(); + TimeProvider::get()->unfreezeTime(); } - public function testRegisterWhenExists() { - $this->service->register('id'); - $this->factoryMock->expects($this->never())->method('create'); - $this->service->register('id'); - $this->assertTrue($this->service->has('id')); + public function testProcessThenOutputSend() { + $this->outputMock->expects($this->once())->method('send') + ->with( + $this->request->getWorkerId(), + $this->request->getCommand(), + false + ); + $this->service->process($this->request); } - public function testUnregisterWhenExists() { - $this->service->register('id'); - $this->outputMock->expects($this->once())->method('close'); - $this->service->unregister('id'); - $this->assertFalse($this->service->has('id')); + public function testProcessThenRequestIsSent() { + $this->service->process($this->request); + $this->assertTrue($this->request->isSent()); } - public function testHasWhenNotExists() { - $this->assertFalse($this->service->has('not_exists')); + public function testProcessThenRequestSentTimeIsNow() { + TimeProvider::get()->freezeTime(); + $this->service->process($this->request); + $this->assertEquals(TimeProvider::get()->now(), $this->request->getSentTime()); } - public function testSendCommandWhenExists() { - $this->service->register('id'); - $command = new BasicCommand('c'); - $this->outputMock->expects($this->once())->method('sendCommand') - ->with($this->identicalTo($command)); - $this->outputMock->expects($this->once())->method('getCommandReply') - ->willReturn(json_encode(CommandReply::success('m'))); - - $reply = $this->service->sendCommand('id', $command); - $this->assertEquals('m', $reply->getMessage()); + public function testProcessThenPendingRequest() { + $this->service->process($this->request); + $this->assertEquals([$this->request], $this->service->getPendingRequests()); } - public function testSendCommandWhenNotExists() { - $command = new BasicCommand('c'); - $this->outputMock->expects($this->never())->method('sendCommand'); - $this->outputMock->expects($this->never())->method('getCommandReply'); - $reply = $this->service->sendCommand('id', $command); - $this->assertEquals('worker not exists', $reply->getMessage()); + public function testProcessWhenSendExceptionThenCallReplyCallbackWithErrorReply() { + $this->outputMock->method('send')->willThrowException(new \Exception('m')); + $this->request->getReplyCallback()->expects($this->once())->method('__invoke') + ->with($this->request, $this->callback(function (CommandReply $reply) { + return $reply->isError(); + })); + $this->service->process($this->request); } - public function testSendCommandWhenReplyTimeout() { - $this->service->register('id'); - $command = new BasicCommand('c'); - $this->outputMock->expects($this->once())->method('getCommandReply'); - TimeProvider::get()->freezeTime(); - $reply = $this->service->sendCommand('id', $command, 0); - $this->assertEquals('reply timeout', $reply->getMessage()); - TimeProvider::get()->unfreezeTime(); + public function testProcessWhenSendExceptionThenNotPendingRequest() { + $this->outputMock->method('send')->willThrowException(new \Exception('m')); + $this->service->process($this->request); + $this->assertEmpty($this->service->getPendingRequests()); } - public function testSendCommandWhenSendCommandException() { - $this->service->register('id'); - $command = new BasicCommand('c'); - $this->outputMock->method('sendCommand') - ->willThrowException(new CommandException('m')); - $reply = $this->service->sendCommand('id', $command); - $this->assertEquals('m', $reply->getMessage()); + public function testProcessWhenSendExceptionThenNotSent() { + $this->outputMock->method('send')->willThrowException(new \Exception('m')); + $this->service->process($this->request); + $this->assertFalse($this->request->isSent()); + } + + public function testDoTickWhenReplyThenCallReplyCallback() { + $this->service->process($this->request); + $reply = CommandReply::success( + $this->request->getCommand()->getCorrelationId(), + 'm' + ); + + $this->inputMock->method('getNext')->willReturn($reply); + $this->request->getReplyCallback()->expects($this->once())->method('__invoke') + ->with($this->request, $reply); + $this->service->tick(); } - public function testSendCommandWhenGetCommandReplyException() { - $this->service->register('id'); - $command = new BasicCommand('c'); - $this->outputMock->method('sendCommand') - ->willThrowException(new CommandException('m')); - $reply = $this->service->sendCommand('id', $command); - $this->assertEquals('m', $reply->getMessage()); + public function testDoTickWhenReplyNotCorrelatedThenIgnore() { + $reply = CommandReply::success( + $this->request->getCommand()->getCorrelationId(), + 'm' + ); + + $this->inputMock->method('getNext')->willReturn($reply); + $this->request->getReplyCallback()->expects($this->never())->method('__invoke'); + $this->service->tick(); + } + + public function testDoTickWhenRequestReplyTimeoutThenCallReplyCallbackWithErrorReply() { + $now = time(); + TimeProvider::get()->freezeTime($now); + $this->service->process($this->request); + TimeProvider::get()->freezeTime($now + $this->request->getReplyTimeout()); + + $this->request->getReplyCallback()->expects($this->once())->method('__invoke') + ->with($this->request, $this->callback(function (CommandReply $reply) { + return $reply->isError(); + })); + $this->service->tick(); } } From 4354e93791a6819cc755ee54403a157913bb0844 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Thu, 13 Oct 2016 16:00:24 +0200 Subject: [PATCH 088/133] refactored --- .../Worker/Manager/WorkerProcessService.php | 109 ++++++++++-------- .../Manager/WorkerProcessServiceTest.php | 55 ++++++--- 2 files changed, 100 insertions(+), 64 deletions(-) diff --git a/src/SAREhub/Component/Worker/Manager/WorkerProcessService.php b/src/SAREhub/Component/Worker/Manager/WorkerProcessService.php index 7ea8899..4460b48 100644 --- a/src/SAREhub/Component/Worker/Manager/WorkerProcessService.php +++ b/src/SAREhub/Component/Worker/Manager/WorkerProcessService.php @@ -2,13 +2,9 @@ namespace SAREhub\Component\Worker\Manager; -use Psr\Log\LoggerAwareInterface; -use Psr\Log\LoggerInterface; -use Psr\Log\NullLogger; +use SAREhub\Component\Worker\Service\ServiceSupport; -class WorkerProcessService implements LoggerAwareInterface { - - private $logger; +class WorkerProcessService extends ServiceSupport { /** * @var WorkerProcessFactory @@ -20,80 +16,103 @@ class WorkerProcessService implements LoggerAwareInterface { */ private $processList = []; - public function __construct(WorkerProcessFactory $factory) { + protected function __construct() { + } + + /** + * @return WorkerProcessService + */ + public static function newInstance() { + return new self(); + } + + /** + * @param WorkerProcessFactory $factory + * @return $this + */ + public function withWorkerProcessFactory(WorkerProcessFactory $factory) { $this->processFactory = $factory; - $this->logger = new NullLogger(); + return $this; + } + + protected function doStart() { + } + protected function doTick() { + } + + + protected function doStop() { + + } /** - * @param string $id + * @param string $workerId * @return WorkerProcess */ - public function register($id) { - if (!$this->has($id)) { - $process = $this->processFactory->create($id); - $this->processList[$id] = $process; - $this->getLogger()->info('registered worker process: '.$id); - return $process; + public function registerWorker($workerId) { + if (!$this->hasWorker($workerId)) { + $this->getLogger()->info("$workerId registering"); + $process = $this->processFactory->create($workerId); + $process->start(); + $this->processList[$workerId] = $process; + $this->getLogger()->info("$workerId registered with PID: ".$process->getPid()); } + + $this->getLogger()->info("$workerId registered before"); } /** - * @param string $id + * @param string $workerId */ - public function unregister($id) { - if ($this->has($id)) { - unset($this->processList[$id]); - $this->getLogger()->info('unregistered worker process: '.$id); + public function unregisterWorker($workerId) { + if ($this->hasWorker($workerId)) { + unset($this->processList[$workerId]); + $this->getLogger()->info("$workerId unregistered"); } } - public function start($id) { - if ($process = $this->get($id)) { - $process->start(); - $this->getLogger()->info('started worker process: '.$id); + public function killWorker($workerId) { + if ($process = $this->get($workerId)) { + $process->kill(); + $this->getLogger()->info("worker process: $workerId killed"); } } - public function kill($id) { - if ($process = $this->get($id)) { - $process->kill(); - $this->getLogger()->info('killed worker process: '.$id); + public function getWorkerPid($workerId) { + if ($process = $this->get($workerId)) { + return $process->getPid(); } + + return 0; } - /** - * @param string $id + * @param string $workerId * @return null|WorkerProcess */ - protected function get($id) { - return $this->has($id) ? $this->processList[$id] : null; + protected function get($workerId) { + return $this->hasWorker($workerId) ? $this->processList[$workerId] : null; } /** - * @param $id + * @param $workerId * @return boolean */ - public function isWorkerRunning($id) { - return $this->get($id)->isRunning(); + public function isWorkerRunning($workerId) { + if ($process = $this->get($workerId)) { + return $process->isRunning(); + } + + return false; } /** * @param string $id * @return bool */ - public function has($id) { + public function hasWorker($id) { return isset($this->processList[$id]); } - /** - * @return LoggerInterface - */ - public function getLogger() { - return $this->logger; - } - public function setLogger(LoggerInterface $logger) { - $this->logger = $logger; - } } \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessServiceTest.php b/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessServiceTest.php index d4d3c63..8772844 100644 --- a/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessServiceTest.php +++ b/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessServiceTest.php @@ -24,40 +24,57 @@ protected function setUp() { $this->factoryMock = $this->createMock(WorkerProcessFactory::class); $this->process = $this->createMock(WorkerProcess::class); $this->factoryMock->method('create')->willReturn($this->process); - $this->service = new WorkerProcessService($this->factoryMock); + $this->service = WorkerProcessService::newInstance() + ->withWorkerProcessFactory($this->factoryMock); } - public function testRegister() { - $this->service->register('uuid'); - $this->assertTrue($this->service->has('uuid')); + public function testRegisterThenHasWorker() { + $this->service->registerWorker('worker'); + $this->assertTrue($this->service->hasWorker('worker')); } - public function testRegisterWhenExists() { - $this->service->register('uuid'); + public function testRegisterThenCreateProcess() { + $this->factoryMock->expects($this->once())->method('create')->willReturn($this->process); + $this->service->registerWorker('worker'); + } + + public function testRegisterThenProcessStart() { + $this->process->expects($this->once())->method('start'); + $this->service->registerWorker('worker'); + } + + public function testRegisterWhenWorkerExistsThenNotCreateProcess() { + $this->service->registerWorker('worker'); $this->factoryMock->expects($this->never())->method('create'); - $this->assertTrue($this->service->has('uuid')); + $this->service->registerWorker('worker'); } - public function testUnregisterWhenExists() { - $this->service->register('worker'); - $this->service->unregister('worker'); - $this->assertFalse($this->service->has('worker')); + public function testRegisterWhenWorkerExistsThenHasOld() { + $this->service->registerWorker('worker'); + $this->service->registerWorker('worker'); + $this->assertTrue($this->service->hasWorker('worker')); } - public function testStartWhenExists() { - $this->service->register('id'); - $this->process->expects($this->once())->method('start'); - $this->service->start('id'); + public function testUnregisterWhenExists() { + $this->service->registerWorker('worker'); + $this->service->unregisterWorker('worker'); + $this->assertFalse($this->service->hasWorker('worker')); } public function testKillWhenExists() { - $this->service->register('id'); + $this->service->registerWorker('id'); $this->process->expects($this->once())->method('kill'); - $this->service->kill('id'); + $this->service->killWorker('id'); + } + + public function testHasWhenNotExistsThenReturnFalse() { + $this->assertFalse($this->service->hasWorker('not_exists')); } - public function testHasWhenNotExists() { - $this->assertFalse($this->service->has('not_exists')); + public function testGetWorkerPidWhenExistsThenReturnPid() { + $this->service->registerWorker('worker'); + $this->process->method('getPid')->willReturn(1000); + $this->assertEquals(1000, $this->service->getWorkerPid('worker')); } } From ebcf6eac3b90bb795a8ecb61e5acbede4308ffd3 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Thu, 13 Oct 2016 16:21:59 +0200 Subject: [PATCH 089/133] fix getLogger --- src/SAREhub/Component/Worker/Service/ServiceSupport.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SAREhub/Component/Worker/Service/ServiceSupport.php b/src/SAREhub/Component/Worker/Service/ServiceSupport.php index b3173ef..81cf999 100644 --- a/src/SAREhub/Component/Worker/Service/ServiceSupport.php +++ b/src/SAREhub/Component/Worker/Service/ServiceSupport.php @@ -93,7 +93,7 @@ public function isRunning() { * Gets logger assigned to that object. * @return LoggerInterface */ - protected function getLogger() { + public function getLogger() { if ($this->logger === null) { $this->logger = new NullLogger(); } From 784abe6fbc43ec5107fc820466f5a682ddcfd371 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Thu, 13 Oct 2016 16:38:06 +0200 Subject: [PATCH 090/133] fixes for async reply --- src/SAREhub/Component/Worker/BasicWorker.php | 6 +- src/SAREhub/Component/Worker/Worker.php | 5 +- .../Component/Worker/WorkerCommands.php | 5 +- src/SAREhub/Component/Worker/WorkerRunner.php | 92 ++++++++----------- .../Component/Worker/BasicWorkerTest.php | 13 +-- .../Component/Worker/WorkerRunnerTest.php | 14 +-- 6 files changed, 53 insertions(+), 82 deletions(-) diff --git a/src/SAREhub/Component/Worker/BasicWorker.php b/src/SAREhub/Component/Worker/BasicWorker.php index f69a306..1930c64 100644 --- a/src/SAREhub/Component/Worker/BasicWorker.php +++ b/src/SAREhub/Component/Worker/BasicWorker.php @@ -20,9 +20,9 @@ public function __construct(WorkerContext $context) { $this->context = $context; } - public function processCommand(Command $command) { + public function processCommand(Command $command, callable $replyCallback) { $this->getLogger()->info('execute command: '.$command); - return $this->doCommand($command); + return $this->doCommand($command, $replyCallback); } /** @@ -30,7 +30,7 @@ public function processCommand(Command $command) { * @param Command $command * @throws WorkerException When something was wrong. */ - protected abstract function doCommand(Command $command); + protected abstract function doCommand(Command $command, callable $replyCallback); public function getId() { return $this->getContext()->getId(); diff --git a/src/SAREhub/Component/Worker/Worker.php b/src/SAREhub/Component/Worker/Worker.php index c8d0329..f5bd7cb 100644 --- a/src/SAREhub/Component/Worker/Worker.php +++ b/src/SAREhub/Component/Worker/Worker.php @@ -3,7 +3,6 @@ namespace SAREhub\Component\Worker; use SAREhub\Component\Worker\Command\Command; -use SAREhub\Component\Worker\Command\CommandReply; use SAREhub\Component\Worker\Service\Service; /** @@ -14,9 +13,9 @@ interface Worker extends Service { /** * Executed when command was received. * @param Command $command - * @return CommandReply command reply + * @param callable $replyCallback */ - public function processCommand(Command $command); + public function processCommand(Command $command, callable $replyCallback); /** * @return string diff --git a/src/SAREhub/Component/Worker/WorkerCommands.php b/src/SAREhub/Component/Worker/WorkerCommands.php index 83bed25..499886a 100644 --- a/src/SAREhub/Component/Worker/WorkerCommands.php +++ b/src/SAREhub/Component/Worker/WorkerCommands.php @@ -9,9 +9,10 @@ class WorkerCommands { const STOP = 'worker.stop'; /** + * @param $correlationId * @return BasicCommand */ - public static function stop() { - return new BasicCommand(self::STOP); + public static function stop($correlationId) { + return new BasicCommand($correlationId, self::STOP); } } \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/WorkerRunner.php b/src/SAREhub/Component/Worker/WorkerRunner.php index a9a7ef3..88f4e82 100644 --- a/src/SAREhub/Component/Worker/WorkerRunner.php +++ b/src/SAREhub/Component/Worker/WorkerRunner.php @@ -2,20 +2,16 @@ namespace SAREhub\Component\Worker; -use Psr\Log\LoggerAwareInterface; -use Psr\Log\LoggerInterface; -use Psr\Log\NullLogger; use SAREhub\Component\Worker\Command\Command; use SAREhub\Component\Worker\Command\CommandInput; use SAREhub\Component\Worker\Command\CommandReply; use SAREhub\Component\Worker\Command\CommandReplyOutput; +use SAREhub\Component\Worker\Service\ServiceSupport; /** * Helper class for run worker. */ -class WorkerRunner implements LoggerAwareInterface { - - private $logger; +class WorkerRunner extends ServiceSupport { /** * @var Worker @@ -30,7 +26,6 @@ class WorkerRunner implements LoggerAwareInterface { private $commandReplyOutput; protected function __construct() { - $this->logger = new NullLogger(); } /** @@ -67,10 +62,12 @@ public function withCommandReplyOutput(CommandReplyOutput $output) { return $this; } + /** - * Starts worker + * Contains custom worker start logic + * @throws \Exception When something was wrong. */ - public function start() { + protected function doStart() { try { $this->getWorker()->start(); } catch (\Exception $e) { @@ -79,9 +76,10 @@ public function start() { } /** - * @return bool + * Contains custom worker tick logic + * @throws \Exception When something was wrong. */ - public function tick() { + protected function doTick() { try { $this->checkCommand(); $this->getWorker()->tick(); @@ -90,61 +88,62 @@ public function tick() { } } - public function stop() { - try { - $this->getWorker()->stop(); - $this->getCommandInput()->close(); - $this->getCommandReplyOutput()->close(); - } catch (\Exception $e) { - $this->getLogger()->error($e); - } - } - private function checkCommand() { if ($command = $this->getCommandInput()->getNext()) { - $reply = $this->processCommand($command); - $this->getLogger()->info('sending reply', ['reply' => $reply]); - $this->getCommandReplyOutput()->send($reply, true); + $runner = $this; + $replyCallback = function (Command $command, CommandReply $reply) use ($runner) { + $runner->getCommandReplyOutput()->send($reply, true); + $runner->getLogger()->info('sending reply', ['reply' => $reply]); + }; + $this->processCommand($command, $replyCallback); } } - - private function processCommand(Command $command) { + private function processCommand(Command $command, callable $replyCallback) { $this->getLogger()->info('process command', ['command' => (string)$command]); try { - $reply = $this->onCommand($command); - if ($reply === null) { - throw new \LogicException('empty reply'); - } + $this->onCommand($command, $replyCallback); } catch (\Exception $e) { - $reply = $this->onProcessCommandException($command, $e); + $this->onProcessCommandException($command, $e, $replyCallback); } - - return $reply; } - private function onCommand(Command $command) { + private function onCommand(Command $command, callable $replyCallback) { switch ($command->getName()) { case WorkerCommands::STOP: - return $this->onStopCommand($command); + $this->onStopCommand($command, $replyCallback); break; default: - return $this->worker->processCommand($command); + $this->worker->processCommand($command, $replyCallback); } } - private function onStopCommand(Command $command) { + private function onStopCommand(Command $command, callable $replyCallback) { $this->getWorker()->stop(); - return CommandReply::success($command->getCorrelationId(), 'stopped'); + $replyCallback($command, CommandReply::success($command->getCorrelationId(), 'stopped')); } - private function onProcessCommandException(Command $command, \Exception $e) { + private function onProcessCommandException(Command $command, \Exception $e, callable $replyCallback) { $this->getLogger()->error($e); - return CommandReply::error( + $replyCallback($command, CommandReply::error( $command->getCorrelationId(), 'exception when execute command', [ 'exceptionMessage' => $e->getMessage() - ]); + ])); + } + + /** + * Contains custom worker stop logic + * @throws \Exception When something was wrong. + */ + protected function doStop() { + try { + $this->getWorker()->stop(); + $this->getCommandInput()->close(); + $this->getCommandReplyOutput()->close(); + } catch (\Exception $e) { + $this->getLogger()->error($e); + } } /** @@ -174,15 +173,4 @@ public function getCommandInput() { public function getCommandReplyOutput() { return $this->commandReplyOutput; } - - /** - * @return LoggerInterface - */ - public function getLogger() { - return $this->logger; - } - - public function setLogger(LoggerInterface $logger) { - $this->logger = $logger; - } } \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/BasicWorkerTest.php b/tests/unit/SAREhub/Component/Worker/BasicWorkerTest.php index 09a1199..1ad4000 100644 --- a/tests/unit/SAREhub/Component/Worker/BasicWorkerTest.php +++ b/tests/unit/SAREhub/Component/Worker/BasicWorkerTest.php @@ -5,7 +5,6 @@ use SAREhub\Component\Worker\BasicWorker; use SAREhub\Component\Worker\Command\BasicCommand; use SAREhub\Component\Worker\Command\Command; -use SAREhub\Component\Worker\Command\CommandReply; class TestBasicWorker extends BasicWorker { @@ -21,7 +20,7 @@ protected function doStop() { } - protected function doCommand(Command $command) { + protected function doCommand(Command $command, callable $replyCallback) { } } @@ -43,22 +42,16 @@ protected function setUp() { public function testProcessCommandThenDoCommand() { $spy = $this->getMethodSpy('doCommand'); - $this->worker->processCommand($this->command); + $this->worker->processCommand($this->command, function () { }); $this->assertEquals(1, $spy->getInvocationCount()); } public function testProcessCommandThenDoCommandWithCommandParameter() { $spy = $this->getMethodSpy('doCommand'); - $this->worker->processCommand($this->command); + $this->worker->processCommand($this->command, function () { }); $this->assertSame($this->command, $spy->getInvocations()[0]->parameters[0]); } - public function testProcessCommandThenReturnReply() { - $expectedReply = CommandReply::success('1', 'r'); - $this->worker->expects($this->once())->method('doCommand')->willReturn($expectedReply); - $this->assertSame($expectedReply, $this->worker->processCommand($this->command)); - } - private function getMethodSpy($method) { $this->worker->expects($methodSpy = $this->any())->method($method); return $methodSpy; diff --git a/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php b/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php index 916cbc9..df40b26 100644 --- a/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php +++ b/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php @@ -31,7 +31,8 @@ public function testTick() { $this->workerRunner->tick(); } - public function testStop() { + public function testStopWhenStarted() { + $this->workerRunner->start(); $this->workerMock->expects($this->once())->method('stop'); $this->commandInputMock->expects($this->once())->method('close'); $this->commandReplyOutputMock->expects($this->once())->method('close'); @@ -64,17 +65,6 @@ public function testTickWhenProcessCommandException() { $this->workerRunner->tick(); } - public function testTickWhenProcessCommandEmptyReply() { - $command = new BasicCommand('1', 'c'); - $this->commandInputMock->expects($this->once())->method('getNext')->willReturn($command); - $this->workerMock->method('processCommand')->willReturn(null); - $this->commandReplyOutputMock->expects($this->once())->method('send') - ->with($this->callback(function (CommandReply $reply) { - return $reply->getMessage() === 'exception when execute command'; - })); - $this->workerRunner->tick(); - } - protected function setUp() { $this->workerMock = $this->createMock(SAREhub\Component\Worker\Worker::class); $this->commandInputMock = $this->createMock(CommandInput::class); From a45aac2f7594ca9210f6c3af145adee731729b2c Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Thu, 13 Oct 2016 16:47:24 +0200 Subject: [PATCH 091/133] deps update --- composer.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index c172bb3..f5e4c41 100644 --- a/composer.json +++ b/composer.json @@ -13,11 +13,13 @@ "phpunit/phpunit": "5.*", "codeclimate/php-test-reporter": "dev-master", "fig-r/psr2r-sniffer": "0.*", - "phpdocumentor/phpdocumentor": "2.*" + "phpdocumentor/phpdocumentor": "2.9.*" }, "require": { "php": "^7.0", + "monolog/monolog": "1.9.*", "symfony/process": "3.1.3 as 2.8.9", + "symfony/console": "3.1.5 as 2.3.28", "sarehub/commons": "0.5.*", "respect/validation": "1.1.*" }, From 38678cb420135a7b1f746783d956d596bbe01d87 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Fri, 14 Oct 2016 09:51:52 +0200 Subject: [PATCH 092/133] fixes --- .../Worker/Manager/ManagerCommands.php | 14 ++- .../Worker/Manager/WorkerManager.php | 100 +++++++++++----- .../Worker/Manager/WorkerProcessService.php | 7 ++ .../Worker/Manager/WorkerManagerTest.php | 113 +++++++++--------- 4 files changed, 147 insertions(+), 87 deletions(-) diff --git a/src/SAREhub/Component/Worker/Manager/ManagerCommands.php b/src/SAREhub/Component/Worker/Manager/ManagerCommands.php index 1a9b97c..ae98de7 100644 --- a/src/SAREhub/Component/Worker/Manager/ManagerCommands.php +++ b/src/SAREhub/Component/Worker/Manager/ManagerCommands.php @@ -25,14 +25,20 @@ class ManagerCommands { const STATS = self::COMMAND_NAME_PREFIX.'stats'; /** + * @param $correltionId * @param $workerId * @return BasicCommand */ - public static function start($workerId) { - return new BasicCommand(self::START, ['id' => $workerId]); + public static function start($correltionId, $workerId) { + return new BasicCommand($correltionId, self::START, ['id' => $workerId]); } - public static function stop($workerId) { - return new BasicCommand(self::STOP, ['id' => $workerId]); + /** + * @param $correltionId + * @param $workerId + * @return BasicCommand + */ + public static function stop($correltionId, $workerId) { + return new BasicCommand($correltionId, self::STOP, ['id' => $workerId]); } } \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Manager/WorkerManager.php b/src/SAREhub/Component/Worker/Manager/WorkerManager.php index 73719ea..b356c81 100644 --- a/src/SAREhub/Component/Worker/Manager/WorkerManager.php +++ b/src/SAREhub/Component/Worker/Manager/WorkerManager.php @@ -28,69 +28,111 @@ public function __construct(WorkerContext $context) { parent::__construct($context); } + /** + * @param WorkerContext $context + * @return WorkerManager + */ + public static function newInstanceWithContext(WorkerContext $context) { + return new self($context); + } + + /** + * @param WorkerCommandService $service + * @return $this + */ public function withCommandService(WorkerCommandService $service) { $this->commandService = $service; return $this; } + /** + * @param WorkerProcessService $service + * @return $this + */ public function withProcessService(WorkerProcessService $service) { $this->processService = $service; return $this; } protected function doStart() { - + $this->getProcessService()->start(); + $this->getCommandService()->start(); } protected function doTick() { - + $this->getProcessService()->tick(); + $this->getCommandService()->tick(); } protected function doStop() { - $this->commandService->stop(); + foreach ($this->getWorkerList() as $workerId) { + $this->doCommand(ManagerCommands::stop($workerId), function () { }); + } + + $this->getProcessService()->stop(); + $this->getCommandService()->stop(); } - protected function doCommand(Command $command) { + protected function doCommand(Command $command, callable $replyCallback) { switch ($command->getName()) { case ManagerCommands::START: - return $this->onStartCommand($command); + $this->onStartCommand($command, $replyCallback); + break; case ManagerCommands::STOP: - return $this->onStopCommand($command); + $this->onStopCommand($command, $replyCallback); + break; + default: + $this->onUnknownCommand($command, $replyCallback); + break; } - - $this->getLogger()->warning('Unknown command ', ['command' => $command]); - return CommandReply::error('unknown command', $command->getName()); } - protected function onStartCommand(Command $command) { + protected function onStartCommand(Command $command, callable $replyCallback) { $id = $command->getParameters()['id']; - $context = ['command' => $command]; + $context = ['command' => (string)$command]; + + $reply = null; - if ($this->getProcessService()->has($id)) { + if ($this->getProcessService()->hasWorker($id)) { $message = 'worker with same id running'; $this->getLogger()->warning($message, $context); - return CommandReply::error($message); + $reply = CommandReply::error($command->getCorrelationId(), $message); + } else { + $this->getProcessService()->registerWorker($id); + $message = 'worker started with PID: '.$this->getProcessService()->getWorkerPid($id); + $this->getLogger()->info($message, $context); + $reply = CommandReply::success($command->getCorrelationId(), $message); } - $this->getProcessService()->register($id); - $this->getProcessService()->start($id); - $this->getCommandService()->register($id); - - $message = 'worker started'; - $this->getLogger()->info($message, $context); - return CommandReply::success($message); + $replyCallback($command, $reply); } - protected function onStopCommand(Command $command) { + protected function onStopCommand(Command $command, callable $replyCallback) { $id = $command->getParameters()['id']; - $this->getLogger()->info('send stop command to worker', ['command' => $command]); - - $reply = $this->getCommandService()->sendCommand($id, WorkerCommands::stop()); - if ($reply->isSuccess()) { - $this->getProcessService()->unregister($id); - $this->getCommandService()->unregister($id); - } - return $reply; + $this->getLogger()->info('send stop command to worker', ['command' => (string)$command]); + $manager = $this; + $request = WorkerCommandRequest::newInstance() + ->withWorkerId($id) + ->withCommand(WorkerCommands::stop($command->getCorrelationId())) + ->withReplyCallback( + function (WorkerCommandRequest $request, CommandReply $reply) use ($manager, $replyCallback) { + $this->getLogger()->info('got reply', ['request' => $request, 'reply' => json_encode($reply)]); + $manager->getProcessService()->unregisterWorker($request->getWorkerId()); + $replyCallback($reply); + }); + $this->getCommandService()->process($request); + } + + protected function onUnknownCommand(Command $command, callable $replyCallback) { + $this->getLogger()->warning('unknown command', ['command' => (string)$command]); + $replyCallback($command, CommandReply::error('unknown command', $command->getName())); + } + + /** + * @return array + */ + public function getWorkerList() { + return $this->getProcessService()->getWorkerList(); } /** diff --git a/src/SAREhub/Component/Worker/Manager/WorkerProcessService.php b/src/SAREhub/Component/Worker/Manager/WorkerProcessService.php index 4460b48..ac87748 100644 --- a/src/SAREhub/Component/Worker/Manager/WorkerProcessService.php +++ b/src/SAREhub/Component/Worker/Manager/WorkerProcessService.php @@ -35,6 +35,13 @@ public function withWorkerProcessFactory(WorkerProcessFactory $factory) { return $this; } + /** + * @return array + */ + public function getWorkerList() { + return array_keys($this->processList); + } + protected function doStart() { } diff --git a/tests/unit/SAREhub/Component/Worker/Manager/WorkerManagerTest.php b/tests/unit/SAREhub/Component/Worker/Manager/WorkerManagerTest.php index 956af81..4a77a2a 100644 --- a/tests/unit/SAREhub/Component/Worker/Manager/WorkerManagerTest.php +++ b/tests/unit/SAREhub/Component/Worker/Manager/WorkerManagerTest.php @@ -4,6 +4,7 @@ use SAREhub\Component\Worker\Command\Command; use SAREhub\Component\Worker\Command\CommandReply; use SAREhub\Component\Worker\Manager\ManagerCommands; +use SAREhub\Component\Worker\Manager\WorkerCommandRequest; use SAREhub\Component\Worker\Manager\WorkerCommandService; use SAREhub\Component\Worker\Manager\WorkerManager; use SAREhub\Component\Worker\Manager\WorkerProcessService; @@ -27,80 +28,84 @@ class WorkerManagerTest extends TestCase { */ private $manager; - protected function setUp() { - parent::setUp(); - $this->processServiceMock = $this->createMock(WorkerProcessService::class); - $this->commandServiceMock = $this->createMock(WorkerCommandService::class); - $this->manager = (new WorkerManager(WorkerContext::newInstance())) - ->withProcessService($this->processServiceMock) - ->withCommandService($this->commandServiceMock); - } + /** + * @var PHPUnit_Framework_MockObject_MockObject + */ + private $replyCallback; public function testStartCommandWhenNotExistsThenSuccess() { $workerId = 'worker1'; - $command = ManagerCommands::start($workerId); - $reply = $this->manager->processCommand($command); - $this->assertTrue($reply->isSuccess()); + $command = ManagerCommands::start('1', $workerId); + $this->assertCommandReply($this->once(), $command, function (CommandReply $reply) { + return $reply->isSuccess(); + }); + + $this->manager->processCommand($command, $this->replyCallback); } public function testStartCommandWhenNotExistsThenRegisterInProcessService() { $workerId = 'worker1'; - $command = ManagerCommands::start($workerId); - $this->processServiceMock->expects($this->once())->method('register')->with($workerId); - $this->manager->processCommand($command); - } - - public function testStartCommandWhenNotExistsThenStartInProcessService() { - $workerId = 'worker1'; - $command = ManagerCommands::start($workerId); - $this->processServiceMock->expects($this->once())->method('start')->with($workerId); - $this->manager->processCommand($command); - } - - public function testStartCommandWhenNotExistsThenRegisterInCommandService() { - $workerId = 'worker1'; - $command = ManagerCommands::start($workerId); - $this->commandServiceMock->expects($this->once())->method('register')->with($workerId); - $this->manager->processCommand($command); + $command = ManagerCommands::start('1', $workerId); + $this->processServiceMock->expects($this->once())->method('registerWorker')->with($workerId); + $this->manager->processCommand($command, $this->replyCallback); } public function testStartCommandWhenExistsThenError() { $workerId = 'worker1'; - $command = ManagerCommands::start($workerId); - $this->processServiceMock->method('has')->with($workerId)->willReturn(true); - $reply = $this->manager->processCommand($command); - $this->assertTrue($reply->isError()); + $command = ManagerCommands::start('1', $workerId); + $this->processServiceMock->method('hasWorker')->with($workerId)->willReturn(true); + + $this->assertCommandReply($this->once(), $command, function (CommandReply $reply) { + return $reply->isError(); + }); + $this->manager->processCommand($command, $this->replyCallback); } public function testStartWorkerCommandWhenExistsThenNotRegisterInProcessService() { $workerId = 'worker1'; - $command = ManagerCommands::start($workerId); - $this->processServiceMock->method('has')->with($workerId)->willReturn(true); - $this->processServiceMock->expects($this->never())->method('register'); - $this->manager->processCommand($command); + $command = ManagerCommands::start('1', $workerId); + $this->processServiceMock->method('hasWorker')->with($workerId)->willReturn(true); + $this->processServiceMock->expects($this->never())->method('registerWorker'); + $this->manager->processCommand($command, $this->replyCallback); } - public function testStartWorkerCommandWhenExistsThenNotRegisterInCommandService() { - $workerId = 'worker1'; - $command = ManagerCommands::start($workerId); - $this->processServiceMock->method('has')->with($workerId)->willReturn(true); - $this->commandServiceMock->expects($this->never())->method('register'); - $this->manager->processCommand($command); + public function testStopWorkerCommandWhenExistsThenCommandServiceProcess() { + $command = ManagerCommands::stop('1', 'worker1'); + $this->commandServiceMock->expects($this->once())->method('process') + ->with($this->callback(function (WorkerCommandRequest $request) use ($command) { + return $request->getWorkerId() === 'worker1' && + $request->getCommand()->getName() === WorkerCommands::STOP && + $request->getCommand()->getCorrelationId() === $command->getCorrelationId(); + })); + $this->manager->processCommand($command, $this->replyCallback); } - public function testStopWorkerCommandWhenExistsThenSendCommand() { - $command = ManagerCommands::stop('worker1'); - $this->commandServiceMock->expects($this->once())->method('sendCommand') - ->with('worker1', $this->callback(function (Command $command) { - return $command->getName() === WorkerCommands::STOP; - }))->willReturn(CommandReply::success('reply')); - $this->manager->processCommand($command); + public function testStopWorkerCommandWhenReplyThenProcessServiceUnregister() { + $this->processServiceMock->expects($this->once())->method('unregisterWorker')->with('worker1'); + $command = ManagerCommands::stop('1', 'worker1'); + + $this->commandServiceMock->expects($this->once())->method('process') + ->with($this->callback(function (WorkerCommandRequest $request) { + ($request->getReplyCallback())($request, CommandReply::success('1', 'm')); + return true; + })); + + $this->manager->processCommand($command, $this->replyCallback); + } + + protected function setUp() { + parent::setUp(); + $this->processServiceMock = $this->createMock(WorkerProcessService::class); + $this->commandServiceMock = $this->createMock(WorkerCommandService::class); + $this->manager = (new WorkerManager(WorkerContext::newInstance())) + ->withProcessService($this->processServiceMock) + ->withCommandService($this->commandServiceMock); + + $this->replyCallback = $this->createPartialMock(stdClass::class, ['__invoke']); } - public function testStopWorkerCommandWhenExistsThenReturnReply() { - $command = ManagerCommands::stop('worker1'); - $expectedReply = CommandReply::success('reply'); - $this->commandServiceMock->method('sendCommand')->willReturn($expectedReply); - $this->assertSame($expectedReply, $this->manager->processCommand($command)); + private function assertCommandReply($invokeTimes, Command $command, callable $callback) { + $this->replyCallback->expects($invokeTimes)->method('__invoke') + ->with($command, $this->callback($callback)); } } From 4d0f87c1e7abef2eef4a71443651508098e58c7f Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Fri, 14 Oct 2016 10:47:06 +0200 Subject: [PATCH 093/133] refactored --- .../Worker/Command/CommandOutputFactory.php | 11 ------ .../Worker/Command/ZmqCommandOutput.php | 25 ++++++++++++- .../Command/ZmqCommandOutputFactory.php | 36 ------------------- .../Worker/Command/ZmqCommandOutputTest.php | 4 ++- 4 files changed, 27 insertions(+), 49 deletions(-) delete mode 100644 src/SAREhub/Component/Worker/Command/CommandOutputFactory.php delete mode 100644 src/SAREhub/Component/Worker/Command/ZmqCommandOutputFactory.php diff --git a/src/SAREhub/Component/Worker/Command/CommandOutputFactory.php b/src/SAREhub/Component/Worker/Command/CommandOutputFactory.php deleted file mode 100644 index cd917e2..0000000 --- a/src/SAREhub/Component/Worker/Command/CommandOutputFactory.php +++ /dev/null @@ -1,11 +0,0 @@ -publisher = $publisher; + return $this; + } + + /** + * @param CommandFormat $format + * @return $this + */ + public function withCommandFormat(CommandFormat $format) { $this->format = $format; + return $this; } public function send($topic, Command $command, $wait = false) { diff --git a/src/SAREhub/Component/Worker/Command/ZmqCommandOutputFactory.php b/src/SAREhub/Component/Worker/Command/ZmqCommandOutputFactory.php deleted file mode 100644 index 71b045a..0000000 --- a/src/SAREhub/Component/Worker/Command/ZmqCommandOutputFactory.php +++ /dev/null @@ -1,36 +0,0 @@ -senderFactory = $senderFactory; - $this->format = $format; - } - - public function create($workerId) { - return new ZmqCommandOutput(($this->senderFactory)($workerId), $this->format); - } - - - /** - * @param \ZMQContext $context - * @param callable $dsnFactory - * @return \Closure - */ - public static function getSenderFactory(\ZMQContext $context, callable $dsnFactory) { - return function ($workerId) use ($context, $dsnFactory) { - return RequestSender::inContext($context)->connect(($dsnFactory)($workerId)); - }; - } -} \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandOutputTest.php b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandOutputTest.php index 9ef8c86..834b137 100644 --- a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandOutputTest.php +++ b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandOutputTest.php @@ -28,7 +28,9 @@ protected function setUp() { $this->publisher = $this->createMock(Publisher::class); $this->commandFormat = $this->createMock(CommandFormat::class); $this->commandFormat->method('marshal')->willReturn('command_data'); - $this->output = new ZmqCommandOutput($this->publisher, $this->commandFormat); + $this->output = ZmqCommandOutput::newInstance() + ->withPublisher($this->publisher) + ->withCommandFormat($this->commandFormat); } public function testSendThenPublisherCallPublish() { From 12a0849ba2ba02180076fe89fc9e2283fe347f58 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Fri, 14 Oct 2016 12:46:05 +0200 Subject: [PATCH 094/133] refactored to more fluent --- .../Worker/Command/ZmqCommandInput.php | 43 ++++++++++++++++--- .../Worker/Command/ZmqCommandInputTest.php | 4 +- 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/src/SAREhub/Component/Worker/Command/ZmqCommandInput.php b/src/SAREhub/Component/Worker/Command/ZmqCommandInput.php index 170f082..06acb52 100644 --- a/src/SAREhub/Component/Worker/Command/ZmqCommandInput.php +++ b/src/SAREhub/Component/Worker/Command/ZmqCommandInput.php @@ -13,32 +13,61 @@ class ZmqCommandInput implements CommandInput { /** * @var Subscriber */ - private $commandSubscriber; + private $subscriber; /** * @var CommandFormat */ private $format; + protected function __construct() { + } + + /** + * @return ZmqCommandInput + */ + public static function newInstance() { + return new self(); + } - public function __construct(Subscriber $commandSubscriber, CommandFormat $format) { - $this->commandSubscriber = $commandSubscriber; + /** + * @param Subscriber $commandSubscriber + * @return $this + */ + public function withCommandSubscriber(Subscriber $commandSubscriber) { + $this->subscriber = $commandSubscriber; + return $this; + } + + /** + * @param CommandFormat $format + * @return $this + */ + public function withCommandFormat(CommandFormat $format) { $this->format = $format; + return $this; } public function getNext($wait = false) { - $commandData = $this->getCommandSubscriber()->receive($wait); + $commandData = $this->getSubscriber()->receive($wait); return ($commandData) ? $this->format->unmarshal($commandData['body']) : null; } public function close() { - $this->getCommandSubscriber()->disconnect(); + $this->getSubscriber()->disconnect(); } /** * @return Subscriber */ - public function getCommandSubscriber() { - return $this->commandSubscriber; + public function getSubscriber() { + return $this->subscriber; + } + + /** + * @return CommandFormat + */ + public function getCommandFormat() { + return $this->format; } } \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandInputTest.php b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandInputTest.php index f982afa..a214369 100644 --- a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandInputTest.php +++ b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandInputTest.php @@ -29,7 +29,9 @@ class ZmqCommandInputTest extends TestCase { protected function setUp() { $this->subscriberMock = $this->createMock(Subscriber::class); $this->commandFormatMock = $this->createMock(CommandFormat::class); - $this->commandInput = new ZmqCommandInput($this->subscriberMock, $this->commandFormatMock); + $this->commandInput = ZmqCommandInput::newInstance() + ->withCommandSubscriber($this->subscriberMock) + ->withCommandFormat($this->commandFormatMock); } public function testGetNextThenSubscriberReceive() { From b27a3891be1b62351339b4661e4307aab33d7c83 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Fri, 14 Oct 2016 12:51:26 +0200 Subject: [PATCH 095/133] refactored to more fluent --- .../Worker/Command/ZmqCommandReplyOutput.php | 28 ++++++++++++++++++- .../Command/ZmqCommandReplyOutputTest.php | 4 ++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/SAREhub/Component/Worker/Command/ZmqCommandReplyOutput.php b/src/SAREhub/Component/Worker/Command/ZmqCommandReplyOutput.php index ade6c24..86378f6 100644 --- a/src/SAREhub/Component/Worker/Command/ZmqCommandReplyOutput.php +++ b/src/SAREhub/Component/Worker/Command/ZmqCommandReplyOutput.php @@ -12,11 +12,37 @@ class ZmqCommandReplyOutput implements CommandReplyOutput { */ private $publisher; + /** + * @var string + */ private $publishTopic; - public function __construct(Publisher $publisher, $publishTopic) { + protected function __construct() { + } + + /** + * @return ZmqCommandReplyOutput + */ + public static function newInstance() { + return new self(); + } + + /** + * @param Publisher $publisher + * @return $this + */ + public function withPublisher(Publisher $publisher) { $this->publisher = $publisher; + return $this; + } + + /** + * @param $publishTopic + * @return $this + */ + public function withPublishTopic($publishTopic) { $this->publishTopic = $publishTopic; + return $this; } public function send(CommandReply $reply, $wait = false) { diff --git a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandReplyOutputTest.php b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandReplyOutputTest.php index 9474365..3fbcafc 100644 --- a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandReplyOutputTest.php +++ b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandReplyOutputTest.php @@ -23,7 +23,9 @@ class ZmqCommandReplyOutputTest extends TestCase { protected function setUp() { parent::setUp(); $this->publisher = $this->createMock(Publisher::class); - $this->output = new ZmqCommandReplyOutput($this->publisher, $this->topic); + $this->output = ZmqCommandReplyOutput::newInstance() + ->withPublisher($this->publisher) + ->withPublishTopic($this->topic); $this->reply = CommandReply::success("id", "reply"); } From f257d42a9e25ec34f0bcaa12089d9c669698d321 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Fri, 14 Oct 2016 13:02:36 +0200 Subject: [PATCH 096/133] refactored to more fluent --- .../Worker/Command/ZmqCommandReplyInput.php | 22 ++++++++++++++----- .../Command/ZmqCommandReplyInputTest.php | 3 ++- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/SAREhub/Component/Worker/Command/ZmqCommandReplyInput.php b/src/SAREhub/Component/Worker/Command/ZmqCommandReplyInput.php index ba2e09f..a8b65bc 100644 --- a/src/SAREhub/Component/Worker/Command/ZmqCommandReplyInput.php +++ b/src/SAREhub/Component/Worker/Command/ZmqCommandReplyInput.php @@ -6,19 +6,31 @@ class ZmqCommandReplyInput implements CommandReplyInput { + /** + * @var Subscriber + */ private $subscriber; + protected function __construct() { + + } + /** - * @param Subscriber $subscriber + * @return ZmqCommandReplyInput */ - public function __construct(Subscriber $subscriber) { - $this->subscriber = $subscriber; + public static function newInstance() { + return new self(); } /** - * @param bool $wait - * @return null|CommandReply + * @param Subscriber $subscriber + * @return $this */ + public function withSubscriber(Subscriber $subscriber) { + $this->subscriber = $subscriber; + return $this; + } + public function getNext($wait = false) { $replyData = $this->subscriber->receive($wait); return ($replyData) ? CommandReply::createFromJson($replyData['body']) : null; diff --git a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandReplyInputTest.php b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandReplyInputTest.php index 1eb4d4b..778ef40 100644 --- a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandReplyInputTest.php +++ b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandReplyInputTest.php @@ -14,7 +14,8 @@ class ZmqCommandReplyInputTest extends TestCase { protected function setUp() { parent::setUp(); $this->subscriber = $this->createMock(Subscriber::class); - $this->input = new ZmqCommandReplyInput($this->subscriber); + $this->input = ZmqCommandReplyInput::newInstance() + ->withSubscriber($this->subscriber); } public function testGetNextThenSubscriberCallReceive() { From baffee19857f3332eac8df0ab7aecd0ccf283c25 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Fri, 14 Oct 2016 15:00:26 +0200 Subject: [PATCH 097/133] added examples --- examples/WorkerManager/example.php | 64 +++++++++++ examples/WorkerManager/workerScript.php | 69 ++++++++++++ examples/run-example | 16 +++ .../Worker/Manager/CommandRequest.php | 101 ++++++++++++++++++ .../Worker/Manager/ManagerCommands.php | 18 ++++ .../Manager/MultiWorkerCommandRequest.php | 13 +++ .../Worker/Manager/WorkerCommandService.php | 4 + .../Worker/Manager/WorkerManager.php | 56 ++++++++-- worker-cli | 32 ++++++ 9 files changed, 363 insertions(+), 10 deletions(-) create mode 100644 examples/WorkerManager/example.php create mode 100644 examples/WorkerManager/workerScript.php create mode 100644 examples/run-example create mode 100644 src/SAREhub/Component/Worker/Manager/CommandRequest.php create mode 100644 src/SAREhub/Component/Worker/Manager/MultiWorkerCommandRequest.php create mode 100644 worker-cli diff --git a/examples/WorkerManager/example.php b/examples/WorkerManager/example.php new file mode 100644 index 0000000..4b3f7b1 --- /dev/null +++ b/examples/WorkerManager/example.php @@ -0,0 +1,64 @@ +withId('manager'); + +$workerProcessService = WorkerProcessService::newInstance() + ->withWorkerProcessFactory(WorkerProcessFactory::newInstance() + ->withRunnerScriptPath(__DIR__.'/workerScript.php')); + + +$zmqContext = new ZMQContext(); +$workerCommandService = WorkerCommandService::newInstance() + ->withCommandOutput(ZmqCommandOutput::newInstance() + ->withPublisher(Publisher::inContext($zmqContext) + ->bind(Dsn::tcp()->endpoint('127.0.0.1:30002')) + ) + ->withCommandFormat(JsonCommandFormat::newInstance())) + ->withCommandReplyInput(ZmqCommandReplyInput::newInstance() + ->withSubscriber(Subscriber::inContext($zmqContext) + ->subscribe('worker.command.reply') + ->connect(Dsn::tcp()->endpoint('127.0.0.1:30001')) + ) + ); + +$workerManager = WorkerManager::newInstanceWithContext($context) + ->withProcessService($workerProcessService) + ->withCommandService($workerCommandService); + +$logger = new Logger('manager'); +$logger->pushHandler(new StreamHandler(__DIR__.'/log', Logger::DEBUG)); +$workerManager->setLogger($logger); + +$workerManager->start(); + +$replyCallback = function ($command, $reply) use ($workerManager) { + $workerManager->getLogger()->info('replyCallback: ', [ + 'command' => $command, + 'reply' => $reply + ]); +}; + +$workerManager->processCommand(ManagerCommands::start('1', 'worker1'), $replyCallback); +$workerManager->processCommand(ManagerCommands::start('2', 'worker2'), $replyCallback); +$workerManager->processCommand(ManagerCommands::start('3', 'worker3'), $replyCallback); + +sleep(20); + +$workerManager->stop(); + + diff --git a/examples/WorkerManager/workerScript.php b/examples/WorkerManager/workerScript.php new file mode 100644 index 0000000..7a7f631 --- /dev/null +++ b/examples/WorkerManager/workerScript.php @@ -0,0 +1,69 @@ +logInfo('doStart'); + } + + protected function doTick() { + $this->logInfo('doTick'); + sleep(1); // hard work simulation + } + + protected function doStop() { + $this->logInfo('doStop'); + } + + protected function doCommand(Command $command, callable $replyCallback) { + $this->logInfo('doCommand: '.$command); + } + + private function logInfo($message) { + $this->getLogger()->info(sprintf($message, $this->getId())); + } +} + +$context = WorkerContext::newInstance() + ->withId($argv[1]) + ->withRootPath(__DIR__); + +$zmqContext = new ZMQContext(); +$runner = WorkerRunner::newInstance() + ->withWorker(new TestWorker($context)) + ->withCommandInput(ZmqCommandInput::newInstance() + ->withCommandSubscriber(Subscriber::inContext($zmqContext) + ->subscribe($context->getId()) + ->connect(Dsn::tcp()->endpoint('127.0.0.1:30002')) + ) + ->withCommandFormat(JsonCommandFormat::newInstance())) + ->withCommandReplyOutput(ZmqCommandReplyOutput::newInstance() + ->withPublisher(Publisher::inContext($zmqContext) + ->bind(Dsn::tcp()->endpoint('127.0.0.1:30001'))) + ->withPublishTopic('worker.command.reply') + ); + +$logger = new Logger($context->getId()); +$logger->pushHandler(new StreamHandler(__DIR__.'/log', Logger::DEBUG)); +$runner->getWorker()->setLogger($logger); +$runner->setLogger($logger); +$runner->start(); +while ($runner->isRunning()) { + $runner->tick(); +} +$runner->stop(); diff --git a/examples/run-example b/examples/run-example new file mode 100644 index 0000000..edcf7df --- /dev/null +++ b/examples/run-example @@ -0,0 +1,16 @@ +#!/usr/bin/env php +"; + return; +} + +$examplePath = __DIR__.'/'.$argv[1].'/example.php'; + +if (file_exists($examplePath)) { + require $examplePath; +} else { + echo "not found example.php for ".$argv[1]." in ".$examplePath; +} \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Manager/CommandRequest.php b/src/SAREhub/Component/Worker/Manager/CommandRequest.php new file mode 100644 index 0000000..e0fbfe9 --- /dev/null +++ b/src/SAREhub/Component/Worker/Manager/CommandRequest.php @@ -0,0 +1,101 @@ +command = $command; + return $this; + } + + public function withReplyTimeout($timeout) { + $this->replyTimeout = $timeout; + return $this; + } + + public function withReplyCallback(callable $callback) { + $this->replyCallback = $callback; + return $this; + } + + public function markAsSent($now) { + $this->sentTime = $now; + } + + /** + * @return bool + */ + public function isSent() { + return $this->getSentTime() > 0; + } + + /** + * @param $now + * @return bool + */ + public function isReplyTimeout($now) { + return $this->isSent() && $now >= ($this->getSentTime() + $this->getReplyTimeout()); + } + + /** + * @return Command + */ + public function getCommand() { + return $this->command; + } + + /** + * @return int + */ + public function getSentTime() { + return $this->sentTime; + } + + /** + * @return int + */ + public function getReplyTimeout() { + return $this->replyTimeout; + } + + /** + * @return callable + */ + public function getReplyCallback() { + return $this->replyCallback; + } +} \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Manager/ManagerCommands.php b/src/SAREhub/Component/Worker/Manager/ManagerCommands.php index ae98de7..5419bd8 100644 --- a/src/SAREhub/Component/Worker/Manager/ManagerCommands.php +++ b/src/SAREhub/Component/Worker/Manager/ManagerCommands.php @@ -13,6 +13,7 @@ class ManagerCommands { const START = self::COMMAND_NAME_PREFIX.'start'; const STOP = self::COMMAND_NAME_PREFIX.'stop'; + const STOP_ALL = self::COMMAND_NAME_PREFIX.'stop_all'; const RELOAD = self::COMMAND_NAME_PREFIX.'reload'; const PAUSE = self::COMMAND_NAME_PREFIX.'pause'; @@ -24,6 +25,8 @@ class ManagerCommands { const INFO = self::COMMAND_NAME_PREFIX.'info'; const STATS = self::COMMAND_NAME_PREFIX.'stats'; + const CUSTOM = self::COMMAND_NAME_PREFIX.'custom'; + /** * @param $correltionId * @param $workerId @@ -41,4 +44,19 @@ public static function start($correltionId, $workerId) { public static function stop($correltionId, $workerId) { return new BasicCommand($correltionId, self::STOP, ['id' => $workerId]); } + + /** + * @param $correltionId + * @return BasicCommand + */ + public static function stopAll($correltionId) { + return new BasicCommand($correltionId, self::STOP_ALL); + } + + public static function custom($correltionId, $workerId, array $commandData) { + return new BasicCommand($correltionId, self::CUSTOM, [ + 'id' => $workerId, + 'command' => $commandData + ]); + } } \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Manager/MultiWorkerCommandRequest.php b/src/SAREhub/Component/Worker/Manager/MultiWorkerCommandRequest.php new file mode 100644 index 0000000..a5c58ba --- /dev/null +++ b/src/SAREhub/Component/Worker/Manager/MultiWorkerCommandRequest.php @@ -0,0 +1,13 @@ +getWorkerList() as $workerId) { - $this->doCommand(ManagerCommands::stop($workerId), function () { }); - } + $this->processCommand(ManagerCommands::stopAll('doStopManager'.TimeProvider::get()->now()), function () { + $this->getProcessService()->stop(); + $this->getCommandService()->stop(); + }); - $this->getProcessService()->stop(); - $this->getCommandService()->stop(); + while (count($this->getWorkerList())) { + $this->doTick(); + } } protected function doCommand(Command $command, callable $replyCallback) { @@ -81,6 +84,9 @@ protected function doCommand(Command $command, callable $replyCallback) { case ManagerCommands::STOP: $this->onStopCommand($command, $replyCallback); break; + case ManagerCommands::STOP_ALL: + $this->onStopAllCommand($command, $replyCallback); + break; default: $this->onUnknownCommand($command, $replyCallback); break; @@ -92,7 +98,6 @@ protected function onStartCommand(Command $command, callable $replyCallback) { $context = ['command' => (string)$command]; $reply = null; - if ($this->getProcessService()->hasWorker($id)) { $message = 'worker with same id running'; $this->getLogger()->warning($message, $context); @@ -115,14 +120,45 @@ protected function onStopCommand(Command $command, callable $replyCallback) { ->withWorkerId($id) ->withCommand(WorkerCommands::stop($command->getCorrelationId())) ->withReplyCallback( - function (WorkerCommandRequest $request, CommandReply $reply) use ($manager, $replyCallback) { + function (WorkerCommandRequest $request, CommandReply $reply) use ($manager, $replyCallback, $command) { $this->getLogger()->info('got reply', ['request' => $request, 'reply' => json_encode($reply)]); $manager->getProcessService()->unregisterWorker($request->getWorkerId()); - $replyCallback($reply); + $replyCallback($command, $reply); }); $this->getCommandService()->process($request); } + public function onStopAllCommand(Command $command, callable $replyCallback) { + $workerList = $this->getWorkerList(); + $replyAll = []; + $inputCommand = $command; + $stopAllCallback = function (Command $command, CommandReply $reply) use ($inputCommand, &$replyAll, &$workerList, $replyCallback) { + unset($workerList[$command->getParameters()['id']]); + $replyAll[] = $reply; + if (count($workerList) === 0) { + $status = CommandReply::SUCCESS_STATUS; + $convertedReply = []; + foreach ($replyAll as $reply) { + if ($reply->isError()) { + $status = CommandReply::ERROR_STATUS; + } + $convertedReply[] = $reply->jsonSerialize(); + } + $replyCallback($inputCommand, CommandReply::reply( + $inputCommand->getCorrelationId(), + $status, + $convertedReply) + ); + } + }; + + foreach ($workerList as $workerId) { + $correlationId = $command->getCorrelationId(); + $managerCommand = ManagerCommands::stop($correlationId, $workerId); + $this->processCommand($managerCommand, $stopAllCallback); + } + } + protected function onUnknownCommand(Command $command, callable $replyCallback) { $this->getLogger()->warning('unknown command', ['command' => (string)$command]); $replyCallback($command, CommandReply::error('unknown command', $command->getName())); @@ -138,14 +174,14 @@ public function getWorkerList() { /** * @return WorkerProcessService */ - protected function getProcessService() { + public function getProcessService() { return $this->processService; } /** * @return WorkerCommandService */ - protected function getCommandService() { + public function getCommandService() { return $this->commandService; } } \ No newline at end of file diff --git a/worker-cli b/worker-cli new file mode 100644 index 0000000..001997e --- /dev/null +++ b/worker-cli @@ -0,0 +1,32 @@ +#!/usr/bin/env php +setName('app:create-users') + // the short description shown while running "php bin/console list" + ->setDescription('Creates new users.') + // the full command description shown when running the command with + // the "--help" option + ->setHelp("This command allows you to create users..."); + } + + protected function execute(InputInterface $input, OutputInterface $output) { + $output->writeln("test"); + } +} + +$application = new Application(); + +$application->add(new CreateUserCommand()); +$application->run(); From 1ec0ef456cd3c7830ab636bab2c1cb4329efb530 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Mon, 17 Oct 2016 09:28:01 +0200 Subject: [PATCH 098/133] fixes --- examples/WorkerManager/example.php | 6 +++--- examples/WorkerManager/workerScript.php | 17 ++++++++++++----- .../Component/Worker/Manager/WorkerManager.php | 4 ++-- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/examples/WorkerManager/example.php b/examples/WorkerManager/example.php index 4b3f7b1..174ee06 100644 --- a/examples/WorkerManager/example.php +++ b/examples/WorkerManager/example.php @@ -26,13 +26,13 @@ $workerCommandService = WorkerCommandService::newInstance() ->withCommandOutput(ZmqCommandOutput::newInstance() ->withPublisher(Publisher::inContext($zmqContext) - ->bind(Dsn::tcp()->endpoint('127.0.0.1:30002')) + ->bind(Dsn::tcp()->endpoint('127.0.0.1:30001')) ) ->withCommandFormat(JsonCommandFormat::newInstance())) ->withCommandReplyInput(ZmqCommandReplyInput::newInstance() ->withSubscriber(Subscriber::inContext($zmqContext) ->subscribe('worker.command.reply') - ->connect(Dsn::tcp()->endpoint('127.0.0.1:30001')) + ->bind(Dsn::tcp()->endpoint('127.0.0.1:30002')) ) ); @@ -57,7 +57,7 @@ $workerManager->processCommand(ManagerCommands::start('2', 'worker2'), $replyCallback); $workerManager->processCommand(ManagerCommands::start('3', 'worker3'), $replyCallback); -sleep(20); +sleep(10); $workerManager->stop(); diff --git a/examples/WorkerManager/workerScript.php b/examples/WorkerManager/workerScript.php index 7a7f631..8cf145f 100644 --- a/examples/WorkerManager/workerScript.php +++ b/examples/WorkerManager/workerScript.php @@ -43,23 +43,26 @@ private function logInfo($message) { ->withId($argv[1]) ->withRootPath(__DIR__); +$logger = new Logger($context->getId()); +$logger->pushHandler(new StreamHandler(__DIR__.'/log', Logger::DEBUG)); + +try { $zmqContext = new ZMQContext(); $runner = WorkerRunner::newInstance() ->withWorker(new TestWorker($context)) ->withCommandInput(ZmqCommandInput::newInstance() ->withCommandSubscriber(Subscriber::inContext($zmqContext) ->subscribe($context->getId()) - ->connect(Dsn::tcp()->endpoint('127.0.0.1:30002')) + ->connect(Dsn::tcp()->endpoint('127.0.0.1:30001')) ) ->withCommandFormat(JsonCommandFormat::newInstance())) ->withCommandReplyOutput(ZmqCommandReplyOutput::newInstance() ->withPublisher(Publisher::inContext($zmqContext) - ->bind(Dsn::tcp()->endpoint('127.0.0.1:30001'))) + ->connect(Dsn::tcp()->endpoint('127.0.0.1:30002'))) ->withPublishTopic('worker.command.reply') ); - -$logger = new Logger($context->getId()); -$logger->pushHandler(new StreamHandler(__DIR__.'/log', Logger::DEBUG)); + + $logger->info("init"); $runner->getWorker()->setLogger($logger); $runner->setLogger($logger); $runner->start(); @@ -67,3 +70,7 @@ private function logInfo($message) { $runner->tick(); } $runner->stop(); + +} catch (Exception $e) { + $logger->error($e); +} \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Manager/WorkerManager.php b/src/SAREhub/Component/Worker/Manager/WorkerManager.php index 0ac6e14..d04766a 100644 --- a/src/SAREhub/Component/Worker/Manager/WorkerManager.php +++ b/src/SAREhub/Component/Worker/Manager/WorkerManager.php @@ -152,9 +152,9 @@ public function onStopAllCommand(Command $command, callable $replyCallback) { } }; + $correlationId = $command->getCorrelationId(); foreach ($workerList as $workerId) { - $correlationId = $command->getCorrelationId(); - $managerCommand = ManagerCommands::stop($correlationId, $workerId); + $managerCommand = ManagerCommands::stop($correlationId.$workerId, $workerId); $this->processCommand($managerCommand, $stopAllCallback); } } From 787209a53e4d42ccf5655733fcf265c423c5caa3 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Mon, 17 Oct 2016 10:50:55 +0200 Subject: [PATCH 099/133] close fix --- src/SAREhub/Component/Worker/Command/ZmqCommandInput.php | 2 +- src/SAREhub/Component/Worker/Command/ZmqCommandOutput.php | 2 +- .../Component/Worker/Command/ZmqCommandReplyInput.php | 8 ++++++-- .../Component/Worker/Command/ZmqCommandReplyOutput.php | 2 +- .../Component/Worker/Command/ZmqCommandInputTest.php | 2 +- .../Component/Worker/Command/ZmqCommandOutputTest.php | 2 +- .../Component/Worker/Command/ZmqCommandReplyInputTest.php | 4 ++-- .../Worker/Command/ZmqCommandReplyOutputTest.php | 2 +- 8 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/SAREhub/Component/Worker/Command/ZmqCommandInput.php b/src/SAREhub/Component/Worker/Command/ZmqCommandInput.php index 06acb52..e1c85e5 100644 --- a/src/SAREhub/Component/Worker/Command/ZmqCommandInput.php +++ b/src/SAREhub/Component/Worker/Command/ZmqCommandInput.php @@ -54,7 +54,7 @@ public function getNext($wait = false) { } public function close() { - $this->getSubscriber()->disconnect(); + $this->getSubscriber()->close(); } /** diff --git a/src/SAREhub/Component/Worker/Command/ZmqCommandOutput.php b/src/SAREhub/Component/Worker/Command/ZmqCommandOutput.php index 2522d03..847a1a0 100644 --- a/src/SAREhub/Component/Worker/Command/ZmqCommandOutput.php +++ b/src/SAREhub/Component/Worker/Command/ZmqCommandOutput.php @@ -50,7 +50,7 @@ public function send($topic, Command $command, $wait = false) { } public function close() { - $this->getPublisher()->unbind(); + $this->publisher->close(); } /** diff --git a/src/SAREhub/Component/Worker/Command/ZmqCommandReplyInput.php b/src/SAREhub/Component/Worker/Command/ZmqCommandReplyInput.php index a8b65bc..cbe58f4 100644 --- a/src/SAREhub/Component/Worker/Command/ZmqCommandReplyInput.php +++ b/src/SAREhub/Component/Worker/Command/ZmqCommandReplyInput.php @@ -32,11 +32,15 @@ public function withSubscriber(Subscriber $subscriber) { } public function getNext($wait = false) { - $replyData = $this->subscriber->receive($wait); + $replyData = $this->getSubscriber()->receive($wait); return ($replyData) ? CommandReply::createFromJson($replyData['body']) : null; } public function close() { - $this->subscriber->disconnect(); + $this->getSubscriber()->close(); + } + + public function getSubscriber() { + return $this->subscriber; } } \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Command/ZmqCommandReplyOutput.php b/src/SAREhub/Component/Worker/Command/ZmqCommandReplyOutput.php index 86378f6..6a60b8f 100644 --- a/src/SAREhub/Component/Worker/Command/ZmqCommandReplyOutput.php +++ b/src/SAREhub/Component/Worker/Command/ZmqCommandReplyOutput.php @@ -50,7 +50,7 @@ public function send(CommandReply $reply, $wait = false) { } public function close() { - $this->publisher->unbind(); + $this->getPublisher()->close(); } /** diff --git a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandInputTest.php b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandInputTest.php index a214369..0598b75 100644 --- a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandInputTest.php +++ b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandInputTest.php @@ -65,7 +65,7 @@ public function testGetNextWhenNotSent() { } public function testClose() { - $this->subscriberMock->expects($this->once())->method('disconnect'); + $this->subscriberMock->expects($this->once())->method('close'); $this->commandInput->close(); } } diff --git a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandOutputTest.php b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandOutputTest.php index 834b137..a7f42ed 100644 --- a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandOutputTest.php +++ b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandOutputTest.php @@ -44,7 +44,7 @@ public function testSendWhenWaitThenPublisherPublishWait() { } public function testCloseThenPublisherCallUnbind() { - $this->publisher->expects($this->once())->method('unbind'); + $this->publisher->expects($this->once())->method('close'); $this->output->close(); } diff --git a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandReplyInputTest.php b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandReplyInputTest.php index 778ef40..3ddbc41 100644 --- a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandReplyInputTest.php +++ b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandReplyInputTest.php @@ -41,8 +41,8 @@ public function testGetNextWhenMessageThenReturnReplyInstance() { $this->assertInstanceOf(CommandReply::class, $this->input->getNext()); } - public function testCloseThenSubscriberDisconnect() { - $this->subscriber->expects($this->once())->method('disconnect'); + public function testCloseThenSubscriberClose() { + $this->subscriber->expects($this->once())->method('close'); $this->input->close(); } diff --git a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandReplyOutputTest.php b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandReplyOutputTest.php index 3fbcafc..40ff1e5 100644 --- a/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandReplyOutputTest.php +++ b/tests/unit/SAREhub/Component/Worker/Command/ZmqCommandReplyOutputTest.php @@ -42,7 +42,7 @@ public function testSendWhenWaitThenPublisherPublishWithWait() { } public function testClose() { - $this->publisher->expects($this->once())->method('unbind'); + $this->publisher->expects($this->once())->method('close'); $this->output->close(); } } From 2c19fd5add18913905d5f93d7764f05d19fe033a Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Mon, 17 Oct 2016 11:21:24 +0200 Subject: [PATCH 100/133] refactored --- .../{Manager => Command}/CommandRequest.php | 38 +++++- .../CommandService.php} | 31 ++--- .../Manager/MultiWorkerCommandRequest.php | 13 -- .../Worker/Manager/WorkerCommandRequest.php | 120 ------------------ .../Worker/Manager/WorkerManager.php | 18 +-- .../Worker/Command/CommandRequestTest.php | 33 +++++ .../CommandServiceTest.php} | 18 +-- .../Manager/WorkerCommandRequestTest.php | 29 ----- .../Worker/Manager/WorkerManagerTest.php | 12 +- 9 files changed, 104 insertions(+), 208 deletions(-) rename src/SAREhub/Component/Worker/{Manager => Command}/CommandRequest.php (75%) rename src/SAREhub/Component/Worker/{Manager/WorkerCommandService.php => Command/CommandService.php} (77%) delete mode 100644 src/SAREhub/Component/Worker/Manager/MultiWorkerCommandRequest.php delete mode 100644 src/SAREhub/Component/Worker/Manager/WorkerCommandRequest.php create mode 100644 tests/unit/SAREhub/Component/Worker/Command/CommandRequestTest.php rename tests/unit/SAREhub/Component/Worker/{Manager/WorkerCommandServiceTest.php => Command/CommandServiceTest.php} (90%) delete mode 100644 tests/unit/SAREhub/Component/Worker/Manager/WorkerCommandRequestTest.php diff --git a/src/SAREhub/Component/Worker/Manager/CommandRequest.php b/src/SAREhub/Component/Worker/Command/CommandRequest.php similarity index 75% rename from src/SAREhub/Component/Worker/Manager/CommandRequest.php rename to src/SAREhub/Component/Worker/Command/CommandRequest.php index e0fbfe9..55fdc68 100644 --- a/src/SAREhub/Component/Worker/Manager/CommandRequest.php +++ b/src/SAREhub/Component/Worker/Command/CommandRequest.php @@ -1,14 +1,16 @@ topic = $topic; + return $this; + } + + /** + * @param Command $command + * @return $this + */ public function withCommand(Command $command) { $this->command = $command; return $this; } + /** + * @param $timeout + * @return $this + */ public function withReplyTimeout($timeout) { $this->replyTimeout = $timeout; return $this; } + /** + * @param callable $callback + * @return $this + */ public function withReplyCallback(callable $callback) { $this->replyCallback = $callback; return $this; @@ -71,6 +97,10 @@ public function isReplyTimeout($now) { return $this->isSent() && $now >= ($this->getSentTime() + $this->getReplyTimeout()); } + public function getTopic() { + return $this->topic; + } + /** * @return Command */ diff --git a/src/SAREhub/Component/Worker/Manager/WorkerCommandService.php b/src/SAREhub/Component/Worker/Command/CommandService.php similarity index 77% rename from src/SAREhub/Component/Worker/Manager/WorkerCommandService.php rename to src/SAREhub/Component/Worker/Command/CommandService.php index 69f5eb8..15cc816 100644 --- a/src/SAREhub/Component/Worker/Manager/WorkerCommandService.php +++ b/src/SAREhub/Component/Worker/Command/CommandService.php @@ -1,14 +1,11 @@ getLogger()->info('sending command request', ['request' => $request]); try { - $this->commandOutput->send($request->getWorkerId(), $request->getCommand(), false); + $this->commandOutput->send($request->getTopic(), $request->getCommand(), false); $request->markAsSent(TimeProvider::get()->now()); $this->pendingRequests[] = $request; } catch (\Exception $e) { @@ -65,10 +62,6 @@ public function process(WorkerCommandRequest $request) { } } - public function processMulti(MultiWorkerCommandRequest $request) { - - } - /** * @return WorkerCommandRequest[] */ @@ -98,10 +91,10 @@ protected function doTick() { if ($reply = $this->getCommandReplyInput()->getNext()) { $this->getLogger()->info('got reply', ['reply' => $reply]); if ($request = $this->getCorrelatedPendingRequest($reply)) { - $this->getLogger()->info('exists correlated command', - ['request' => $request], - ['reply' => $reply] - ); + $this->getLogger()->info('exists correlated command', [ + 'request' => $request, + 'reply' => $reply + ]); ($request->getReplyCallback())($request, $reply); } $this->getLogger()->info('not exists correlated command for reply', ['reply' => $reply]); @@ -113,7 +106,7 @@ protected function doTick() { protected function doStop() { } - private function onRequestException(WorkerCommandRequest $request, \Exception $exception) { + private function onRequestException(CommandRequest $request, \Exception $exception) { $this->getLogger()->error($exception, ['request' => $request]); $reply = CommandReply::error( $request->getCommand()->getCorrelationId(), @@ -125,7 +118,7 @@ private function onRequestException(WorkerCommandRequest $request, \Exception $e /** * @param CommandReply $reply - * @return null|WorkerCommandRequest + * @return null|CommandRequest */ private function getCorrelatedPendingRequest(CommandReply $reply) { foreach ($this->getPendingRequests() as $request) { diff --git a/src/SAREhub/Component/Worker/Manager/MultiWorkerCommandRequest.php b/src/SAREhub/Component/Worker/Manager/MultiWorkerCommandRequest.php deleted file mode 100644 index a5c58ba..0000000 --- a/src/SAREhub/Component/Worker/Manager/MultiWorkerCommandRequest.php +++ /dev/null @@ -1,13 +0,0 @@ -workerId = $id; - return $this; - } - - public function withCommand(Command $command) { - $this->command = $command; - return $this; - } - - public function withReplyTimeout($timeout) { - $this->replyTimeout = $timeout; - return $this; - } - - public function withReplyCallback(callable $callback) { - $this->replyCallback = $callback; - return $this; - } - - public function markAsSent($now) { - $this->sentTime = $now; - } - - /** - * @return bool - */ - public function isSent() { - return $this->getSentTime() > 0; - } - - /** - * @param $now - * @return bool - */ - public function isReplyTimeout($now) { - return $this->isSent() && $now >= ($this->getSentTime() + $this->getReplyTimeout()); - } - - /** - * @return string - */ - public function getWorkerId() { - return $this->workerId; - } - - /** - * @return Command - */ - public function getCommand() { - return $this->command; - } - - /** - * @return int - */ - public function getSentTime() { - return $this->sentTime; - } - - /** - * @return int - */ - public function getReplyTimeout() { - return $this->replyTimeout; - } - - /** - * @return callable - */ - public function getReplyCallback() { - return $this->replyCallback; - } - -} \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Manager/WorkerManager.php b/src/SAREhub/Component/Worker/Manager/WorkerManager.php index d04766a..7fd85fb 100644 --- a/src/SAREhub/Component/Worker/Manager/WorkerManager.php +++ b/src/SAREhub/Component/Worker/Manager/WorkerManager.php @@ -6,6 +6,8 @@ use SAREhub\Component\Worker\BasicWorker; use SAREhub\Component\Worker\Command\Command; use SAREhub\Component\Worker\Command\CommandReply; +use SAREhub\Component\Worker\Command\CommandRequest; +use SAREhub\Component\Worker\Command\CommandService; use SAREhub\Component\Worker\WorkerCommands; use SAREhub\Component\Worker\WorkerContext; @@ -16,7 +18,7 @@ class WorkerManager extends BasicWorker { /** - * @var WorkerCommandService + * @var CommandService */ private $commandService; @@ -38,10 +40,10 @@ public static function newInstanceWithContext(WorkerContext $context) { } /** - * @param WorkerCommandService $service + * @param CommandService $service * @return $this */ - public function withCommandService(WorkerCommandService $service) { + public function withCommandService(CommandService $service) { $this->commandService = $service; return $this; } @@ -116,13 +118,13 @@ protected function onStopCommand(Command $command, callable $replyCallback) { $id = $command->getParameters()['id']; $this->getLogger()->info('send stop command to worker', ['command' => (string)$command]); $manager = $this; - $request = WorkerCommandRequest::newInstance() - ->withWorkerId($id) + $request = CommandRequest::newInstance() + ->withTopic($id) ->withCommand(WorkerCommands::stop($command->getCorrelationId())) ->withReplyCallback( - function (WorkerCommandRequest $request, CommandReply $reply) use ($manager, $replyCallback, $command) { + function (CommandRequest $request, CommandReply $reply) use ($manager, $replyCallback, $command) { $this->getLogger()->info('got reply', ['request' => $request, 'reply' => json_encode($reply)]); - $manager->getProcessService()->unregisterWorker($request->getWorkerId()); + $manager->getProcessService()->unregisterWorker($request->getTopic()); $replyCallback($command, $reply); }); $this->getCommandService()->process($request); @@ -179,7 +181,7 @@ public function getProcessService() { } /** - * @return WorkerCommandService + * @return CommandService */ public function getCommandService() { return $this->commandService; diff --git a/tests/unit/SAREhub/Component/Worker/Command/CommandRequestTest.php b/tests/unit/SAREhub/Component/Worker/Command/CommandRequestTest.php new file mode 100644 index 0000000..e5db4c2 --- /dev/null +++ b/tests/unit/SAREhub/Component/Worker/Command/CommandRequestTest.php @@ -0,0 +1,33 @@ +request = CommandRequest::newInstance(); + } + + public function testIsSentThenReturnFalse() { + $this->assertFalse($this->request->isSent()); + } + + public function testMarkAsSentThenIsSentReturnTrue() { + $this->request->markAsSent(time()); + $this->assertTrue($this->request->isSent()); + } + + public function testIsReplyTimeoutWhenNotSentThenReturnFalse() { + $this->assertFalse($this->request->isReplyTimeout(time())); + } + + public function testIsReplyTimeoutWhenSentAndNotTimeoutThenReturnFalse() { + $now = time(); + $this->request->markAsSent($now); + $this->assertFalse($this->request->isReplyTimeout($now)); + } +} diff --git a/tests/unit/SAREhub/Component/Worker/Manager/WorkerCommandServiceTest.php b/tests/unit/SAREhub/Component/Worker/Command/CommandServiceTest.php similarity index 90% rename from tests/unit/SAREhub/Component/Worker/Manager/WorkerCommandServiceTest.php rename to tests/unit/SAREhub/Component/Worker/Command/CommandServiceTest.php index e1ff469..243c825 100644 --- a/tests/unit/SAREhub/Component/Worker/Manager/WorkerCommandServiceTest.php +++ b/tests/unit/SAREhub/Component/Worker/Command/CommandServiceTest.php @@ -6,10 +6,10 @@ use SAREhub\Component\Worker\Command\CommandOutput; use SAREhub\Component\Worker\Command\CommandReply; use SAREhub\Component\Worker\Command\CommandReplyInput; -use SAREhub\Component\Worker\Manager\WorkerCommandRequest; -use SAREhub\Component\Worker\Manager\WorkerCommandService; +use SAREhub\Component\Worker\Command\CommandRequest; +use SAREhub\Component\Worker\Command\CommandService; -class WorkerCommandServiceTest extends TestCase { +class CommandServiceTest extends TestCase { /** * @var PHPUnit_Framework_MockObject_MockObject @@ -22,12 +22,12 @@ class WorkerCommandServiceTest extends TestCase { private $inputMock; /** - * @var WorkerCommandService + * @var CommandService */ private $service; /** - * @var WorkerCommandRequest + * @var CommandRequest */ private $request; @@ -35,14 +35,14 @@ protected function setUp() { parent::setUp(); $this->outputMock = $this->createMock(CommandOutput::class); $this->inputMock = $this->createMock(CommandReplyInput::class); - $this->service = WorkerCommandService::newInstance() + $this->service = CommandService::newInstance() ->withCommandOutput($this->outputMock) ->withCommandReplyInput($this->inputMock); $this->service->start(); - $this->request = WorkerCommandRequest::newInstance() - ->withWorkerId('worker1') + $this->request = CommandRequest::newInstance() + ->withTopic('worker1') ->withCommand(new BasicCommand('1', 'c')) ->withReplyCallback($this->createPartialMock(stdClass::class, ['__invoke'])); } @@ -55,7 +55,7 @@ protected function tearDown() { public function testProcessThenOutputSend() { $this->outputMock->expects($this->once())->method('send') ->with( - $this->request->getWorkerId(), + $this->request->getTopic(), $this->request->getCommand(), false ); diff --git a/tests/unit/SAREhub/Component/Worker/Manager/WorkerCommandRequestTest.php b/tests/unit/SAREhub/Component/Worker/Manager/WorkerCommandRequestTest.php deleted file mode 100644 index 2f28599..0000000 --- a/tests/unit/SAREhub/Component/Worker/Manager/WorkerCommandRequestTest.php +++ /dev/null @@ -1,29 +0,0 @@ -assertFalse(WorkerCommandRequest::newInstance()->isSent()); - } - - public function testMarkAsSentThenIsSentReturnTrue() { - $request = WorkerCommandRequest::newInstance(); - $request->markAsSent(time()); - $this->assertTrue($request->isSent()); - } - - public function testIsReplyTimeoutWhenNotSentThenReturnFalse() { - $request = WorkerCommandRequest::newInstance(); - $this->assertFalse($request->isReplyTimeout(time())); - } - - public function testIsReplyTimeoutWhenSentAndNotTimeoutThenReturnFalse() { - $request = WorkerCommandRequest::newInstance(); - $now = time(); - $request->markAsSent($now); - $this->assertFalse($request->isReplyTimeout($now)); - } -} diff --git a/tests/unit/SAREhub/Component/Worker/Manager/WorkerManagerTest.php b/tests/unit/SAREhub/Component/Worker/Manager/WorkerManagerTest.php index 4a77a2a..167acac 100644 --- a/tests/unit/SAREhub/Component/Worker/Manager/WorkerManagerTest.php +++ b/tests/unit/SAREhub/Component/Worker/Manager/WorkerManagerTest.php @@ -3,9 +3,9 @@ use PHPUnit\Framework\TestCase; use SAREhub\Component\Worker\Command\Command; use SAREhub\Component\Worker\Command\CommandReply; +use SAREhub\Component\Worker\Command\CommandRequest; +use SAREhub\Component\Worker\Command\CommandService; use SAREhub\Component\Worker\Manager\ManagerCommands; -use SAREhub\Component\Worker\Manager\WorkerCommandRequest; -use SAREhub\Component\Worker\Manager\WorkerCommandService; use SAREhub\Component\Worker\Manager\WorkerManager; use SAREhub\Component\Worker\Manager\WorkerProcessService; use SAREhub\Component\Worker\WorkerCommands; @@ -72,8 +72,8 @@ public function testStartWorkerCommandWhenExistsThenNotRegisterInProcessService( public function testStopWorkerCommandWhenExistsThenCommandServiceProcess() { $command = ManagerCommands::stop('1', 'worker1'); $this->commandServiceMock->expects($this->once())->method('process') - ->with($this->callback(function (WorkerCommandRequest $request) use ($command) { - return $request->getWorkerId() === 'worker1' && + ->with($this->callback(function (CommandRequest $request) use ($command) { + return $request->getTopic() === 'worker1' && $request->getCommand()->getName() === WorkerCommands::STOP && $request->getCommand()->getCorrelationId() === $command->getCorrelationId(); })); @@ -85,7 +85,7 @@ public function testStopWorkerCommandWhenReplyThenProcessServiceUnregister() { $command = ManagerCommands::stop('1', 'worker1'); $this->commandServiceMock->expects($this->once())->method('process') - ->with($this->callback(function (WorkerCommandRequest $request) { + ->with($this->callback(function (CommandRequest $request) { ($request->getReplyCallback())($request, CommandReply::success('1', 'm')); return true; })); @@ -96,7 +96,7 @@ public function testStopWorkerCommandWhenReplyThenProcessServiceUnregister() { protected function setUp() { parent::setUp(); $this->processServiceMock = $this->createMock(WorkerProcessService::class); - $this->commandServiceMock = $this->createMock(WorkerCommandService::class); + $this->commandServiceMock = $this->createMock(CommandService::class); $this->manager = (new WorkerManager(WorkerContext::newInstance())) ->withProcessService($this->processServiceMock) ->withCommandService($this->commandServiceMock); From 17797d1eafa7c485877a00bf09c774dd313a1aeb Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Mon, 17 Oct 2016 12:26:46 +0200 Subject: [PATCH 101/133] stop fix --- .../Component/Worker/Command/CommandService.php | 6 ++++-- .../Component/Worker/Command/CommandServiceTest.php | 10 ++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/SAREhub/Component/Worker/Command/CommandService.php b/src/SAREhub/Component/Worker/Command/CommandService.php index 15cc816..e6f1d16 100644 --- a/src/SAREhub/Component/Worker/Command/CommandService.php +++ b/src/SAREhub/Component/Worker/Command/CommandService.php @@ -63,7 +63,7 @@ public function process(CommandRequest $request) { } /** - * @return WorkerCommandRequest[] + * @return CommandRequest[] */ public function getPendingRequests() { return $this->pendingRequests; @@ -104,6 +104,8 @@ protected function doTick() { } protected function doStop() { + $this->getCommandOutput()->close(); + $this->getCommandReplyInput()->close(); } private function onRequestException(CommandRequest $request, \Exception $exception) { @@ -118,7 +120,7 @@ private function onRequestException(CommandRequest $request, \Exception $excepti /** * @param CommandReply $reply - * @return null|CommandRequest + * @return CommandRequest|null */ private function getCorrelatedPendingRequest(CommandReply $reply) { foreach ($this->getPendingRequests() as $request) { diff --git a/tests/unit/SAREhub/Component/Worker/Command/CommandServiceTest.php b/tests/unit/SAREhub/Component/Worker/Command/CommandServiceTest.php index 243c825..0df6cd8 100644 --- a/tests/unit/SAREhub/Component/Worker/Command/CommandServiceTest.php +++ b/tests/unit/SAREhub/Component/Worker/Command/CommandServiceTest.php @@ -135,4 +135,14 @@ public function testDoTickWhenRequestReplyTimeoutThenCallReplyCallbackWithErrorR })); $this->service->tick(); } + + public function testStopThenCommandOutputClose() { + $this->outputMock->expects($this->once())->method('close'); + $this->service->stop(); + } + + public function testStopThenCommandReplyInputClose() { + $this->inputMock->expects($this->once())->method('close'); + $this->service->stop(); + } } From 0fde1a8b4f70b90495117bd01a4ed87cb1e5fc85 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Tue, 18 Oct 2016 16:15:52 +0200 Subject: [PATCH 102/133] added pcntl support --- src/SAREhub/Component/Worker/WorkerRunner.php | 33 ++++++++++++++++++ .../Component/Worker/WorkerRunnerTest.php | 34 +++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/src/SAREhub/Component/Worker/WorkerRunner.php b/src/SAREhub/Component/Worker/WorkerRunner.php index 88f4e82..1d24170 100644 --- a/src/SAREhub/Component/Worker/WorkerRunner.php +++ b/src/SAREhub/Component/Worker/WorkerRunner.php @@ -2,6 +2,7 @@ namespace SAREhub\Component\Worker; +use SAREhub\Commons\Process\PcntlSignals; use SAREhub\Component\Worker\Command\Command; use SAREhub\Component\Worker\Command\CommandInput; use SAREhub\Component\Worker\Command\CommandReply; @@ -23,9 +24,18 @@ class WorkerRunner extends ServiceSupport { */ private $commandInput; + /** + * @var CommandReplyOutput + */ private $commandReplyOutput; + /** + * @var PcntlSignals + */ + private $signals; + protected function __construct() { + $this->signals = new PcntlSignals(); } /** @@ -62,6 +72,20 @@ public function withCommandReplyOutput(CommandReplyOutput $output) { return $this; } + /** + * Use for handle system signals. For works you must install signals, after it. + * @param PcntlSignals|null $signals the signals handler. When null will use Global handler + * @param bool $install When true will install signals. + * @return $this + */ + public function usePcntl(PcntlSignals $signals = null, $install = true) { + $this->signals = ($signals) ? $signals : PcntlSignals::getGlobal(); + $this->signals->handle(PcntlSignals::SIGINT, array($this, 'stop')); + if ($install) { + $this->signals->install(); + } + return $this; + } /** * Contains custom worker start logic @@ -86,6 +110,8 @@ protected function doTick() { } catch (\Exception $e) { $this->getLogger()->error($e); } + + $this->getPcntlSignals()->checkPendingSignals(); } private function checkCommand() { @@ -173,4 +199,11 @@ public function getCommandInput() { public function getCommandReplyOutput() { return $this->commandReplyOutput; } + + /** + * @return PcntlSignals + */ + public function getPcntlSignals() { + return $this->signals; + } } \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php b/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php index df40b26..7a774d2 100644 --- a/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php +++ b/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php @@ -1,6 +1,7 @@ workerRunner->tick(); } + public function testTickThenCheckPendingSignals() { + echo extension_loaded('pcntl'); + $signals = $this->createMock(PcntlSignals::class); + $signals->expects($this->once())->method('checkPendingSignals'); + $this->workerRunner->usePcntl($signals); + $this->workerRunner->tick(); + var_dump($signals === $this->workerRunner->getPcntlSignals()); + } + + public function testUsePcntlThenHandleSIGINT() { + $runner = $this->workerRunner; + $signals = $this->createMock(PcntlSignals::class); + $signals->expects($this->once())->method('handle') + ->with(PcntlSignals::SIGINT, $this->callback(function (array $callback) use ($runner) { + return $callback[0] === $runner && $callback[1] === 'stop'; + })); + $runner->usePcntl($signals); + } + + public function testUsePcntlWhenInstallTrueThenInstall() { + $runner = $this->workerRunner; + $signals = $this->createMock(PcntlSignals::class); + $signals->expects($this->once())->method('install'); + $runner->usePcntl($signals); + } + + public function testUsePcntlWhenInstallFalseThenInstall() { + $runner = $this->workerRunner; + $signals = $this->createMock(PcntlSignals::class); + $signals->expects($this->never())->method('install'); + $runner->usePcntl($signals, false); + } + protected function setUp() { $this->workerMock = $this->createMock(SAREhub\Component\Worker\Worker::class); $this->commandInputMock = $this->createMock(CommandInput::class); From 217bd65db9bc1d99e346637190e0c483476079b5 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Tue, 18 Oct 2016 16:16:28 +0200 Subject: [PATCH 103/133] fix in WorkerRunner test --- tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php b/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php index 7a774d2..3e2ce83 100644 --- a/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php +++ b/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php @@ -72,7 +72,6 @@ public function testTickThenCheckPendingSignals() { $signals->expects($this->once())->method('checkPendingSignals'); $this->workerRunner->usePcntl($signals); $this->workerRunner->tick(); - var_dump($signals === $this->workerRunner->getPcntlSignals()); } public function testUsePcntlThenHandleSIGINT() { From 815a692ff35902250f22ac07df092945fed2b143 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Tue, 18 Oct 2016 16:21:22 +0200 Subject: [PATCH 104/133] added logging start&stop steps and throws exception when sets same logger instance --- src/SAREhub/Component/Worker/Service/ServiceSupport.php | 7 +++++++ .../Component/Worker/Service/ServiceSupportTest.php | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/src/SAREhub/Component/Worker/Service/ServiceSupport.php b/src/SAREhub/Component/Worker/Service/ServiceSupport.php index 81cf999..5c6db7b 100644 --- a/src/SAREhub/Component/Worker/Service/ServiceSupport.php +++ b/src/SAREhub/Component/Worker/Service/ServiceSupport.php @@ -22,9 +22,11 @@ abstract class ServiceSupport implements Service, LoggerAwareInterface { */ public function start() { if (!$this->isStarted()) { + $this->getLogger()->info('service starting ...'); $this->doStart(); $this->started = true; $this->stopped = false; + $this->getLogger()->info('service started'); } } @@ -56,9 +58,11 @@ protected abstract function doTick(); */ public function stop() { if ($this->isStarted()) { + $this->getLogger()->info('service stopping ...'); $this->doStop(); $this->started = false; $this->stopped = true; + $this->getLogger()->info('service stopped'); } } @@ -102,6 +106,9 @@ public function getLogger() { } public function setLogger(LoggerInterface $logger) { + if ($this->getLogger() === $logger) { + throw new \LogicException('set same logger instance'); + } $this->logger = $logger; } } \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Service/ServiceSupportTest.php b/tests/unit/SAREhub/Component/Worker/Service/ServiceSupportTest.php index 6e2146a..6272eea 100644 --- a/tests/unit/SAREhub/Component/Worker/Service/ServiceSupportTest.php +++ b/tests/unit/SAREhub/Component/Worker/Service/ServiceSupportTest.php @@ -1,6 +1,7 @@ assertFalse($spy->hasBeenInvoked()); } + public function testSetLoggerWhenSetsAndSetSameThenException() { + $logger = new NullLogger(); + $this->service->setLogger($logger); + $this->expectException(\LogicException::class); + $this->service->setLogger($logger); + } + private function getMethodSpy($method) { $this->service->expects($methodSpy = $this->any())->method($method); return $methodSpy; From 3d966928f83a0ed7d2cd57349adf10243cfe7c8e Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Tue, 18 Oct 2016 16:21:51 +0200 Subject: [PATCH 105/133] refactored --- examples/WorkerManager/example.php | 4 ++-- examples/WorkerManager/workerScript.php | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/WorkerManager/example.php b/examples/WorkerManager/example.php index 174ee06..a29e67f 100644 --- a/examples/WorkerManager/example.php +++ b/examples/WorkerManager/example.php @@ -5,6 +5,7 @@ use SAREhub\Commons\Misc\Dsn; use SAREhub\Commons\Zmq\PublishSubscribe\Publisher; use SAREhub\Commons\Zmq\PublishSubscribe\Subscriber; +use SAREhub\Component\Worker\Command\CommandService; use SAREhub\Component\Worker\Command\JsonCommandFormat; use SAREhub\Component\Worker\Command\ZmqCommandOutput; use SAREhub\Component\Worker\Command\ZmqCommandReplyInput; @@ -21,9 +22,8 @@ ->withWorkerProcessFactory(WorkerProcessFactory::newInstance() ->withRunnerScriptPath(__DIR__.'/workerScript.php')); - $zmqContext = new ZMQContext(); -$workerCommandService = WorkerCommandService::newInstance() +$workerCommandService = CommandService::newInstance() ->withCommandOutput(ZmqCommandOutput::newInstance() ->withPublisher(Publisher::inContext($zmqContext) ->bind(Dsn::tcp()->endpoint('127.0.0.1:30001')) diff --git a/examples/WorkerManager/workerScript.php b/examples/WorkerManager/workerScript.php index 8cf145f..91a8676 100644 --- a/examples/WorkerManager/workerScript.php +++ b/examples/WorkerManager/workerScript.php @@ -62,7 +62,6 @@ private function logInfo($message) { ->withPublishTopic('worker.command.reply') ); - $logger->info("init"); $runner->getWorker()->setLogger($logger); $runner->setLogger($logger); $runner->start(); From 0f0272434d5b30efa43aaa561035d3b9be9c4d8a Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Wed, 19 Oct 2016 09:58:10 +0200 Subject: [PATCH 106/133] added SystemdHelper --- .../Component/Worker/Cli/SystemdHelper.php | 29 +++++++++++++++++++ .../Worker/Cli/SystemdHelperTest.php | 28 ++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 src/SAREhub/Component/Worker/Cli/SystemdHelper.php create mode 100644 tests/unit/SAREhub/Component/Worker/Cli/SystemdHelperTest.php diff --git a/src/SAREhub/Component/Worker/Cli/SystemdHelper.php b/src/SAREhub/Component/Worker/Cli/SystemdHelper.php new file mode 100644 index 0000000..75187ce --- /dev/null +++ b/src/SAREhub/Component/Worker/Cli/SystemdHelper.php @@ -0,0 +1,29 @@ +exec('systemctl start '.$unitName); + } + + /** + * @param string $path + * @return string + */ + public function escape($path) { + return $this->exec('systemd-escape '.$path); + } + + /** + * @param string $command + * @return string + */ + public function exec($command) { + return shell_exec($command); + } +} \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Cli/SystemdHelperTest.php b/tests/unit/SAREhub/Component/Worker/Cli/SystemdHelperTest.php new file mode 100644 index 0000000..da48611 --- /dev/null +++ b/tests/unit/SAREhub/Component/Worker/Cli/SystemdHelperTest.php @@ -0,0 +1,28 @@ +helper = $this->createPartialMock(SystemdHelper::class, ['exec']); + } + + public function testStart() { + $this->helper->expects($this->once())->method('exec')->with('systemctl start unit'); + $this->helper->start('unit'); + } + + public function testEscape() { + $this->helper->expects($this->once())->method('exec') + ->with('systemd-escape path')->willReturn('escaped'); + $this->assertEquals('escaped', $this->helper->escape('path')); + } +} From f99a84adaf0bdec48e3b592fc1c17f941725e9b3 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Wed, 19 Oct 2016 09:59:09 +0200 Subject: [PATCH 107/133] added CliBootstrap --- .../Component/Worker/Cli/CliBootstrap.php | 111 ++++++++++++++++++ .../Component/Worker/Cli/CliBootstrapTest.php | 45 +++++++ 2 files changed, 156 insertions(+) create mode 100644 src/SAREhub/Component/Worker/Cli/CliBootstrap.php create mode 100644 tests/unit/SAREhub/Component/Worker/Cli/CliBootstrapTest.php diff --git a/src/SAREhub/Component/Worker/Cli/CliBootstrap.php b/src/SAREhub/Component/Worker/Cli/CliBootstrap.php new file mode 100644 index 0000000..1321517 --- /dev/null +++ b/src/SAREhub/Component/Worker/Cli/CliBootstrap.php @@ -0,0 +1,111 @@ +application = $application; + return $this; + } + + /** + * @param CommandService $service + * @return $this + */ + public function withCommandService(CommandService $service) { + $this->commandService = $service; + return $this; + } + + /** + * @param string $id + * @return $this + */ + public function withSessionId($id) { + $this->sessionId = $id; + return $this; + } + + /** + * @param Parameters $config + * @return $this + */ + public function withConfig(Parameters $config) { + $this->config = $config; + return $this; + } + + public function run() { + $this->getCommandService()->start(); + $this->getApplication()->run(); + $this->getCommandService()->stop(); + } + + public function registerCommand(CliCommand $command) { + $command->withBootstrap($this); + $this->getApplication()->add($command); + + return $this; + } + + /** + * @return Application + */ + public function getApplication() { + return $this->application; + } + + /** + * @return CommandService + */ + public function getCommandService() { + return $this->commandService; + } + + /** + * @return string + */ + public function getSessionId() { + return $this->sessionId; + } + + /** + * @return Parameters + */ + public function getConfig() { + return $this->config; + } +} \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Cli/CliBootstrapTest.php b/tests/unit/SAREhub/Component/Worker/Cli/CliBootstrapTest.php new file mode 100644 index 0000000..4287059 --- /dev/null +++ b/tests/unit/SAREhub/Component/Worker/Cli/CliBootstrapTest.php @@ -0,0 +1,45 @@ +application = $this->createMock(Application::class); + $this->commandService = $this->createMock(CommandService::class); + + $this->bootstrap = CliBootstrap::newInstance() + ->withApplication($this->application) + ->withCommandService($this->commandService); + } + + public function testRunThenCommandServiceStart() { + $this->commandService->expects($this->once())->method('start'); + $this->bootstrap->run(); + } + + public function testRunThenApplicationRun() { + $this->application->expects($this->once())->method('run'); + $this->bootstrap->run(); + } + + public function testRunThenCommandServiceStop() { + $this->commandService->expects($this->once())->method('stop'); + $this->bootstrap->run(); + } + + +} From 34d4e1fa04c64b3fbc1448bb19d69c847fd5b322 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Wed, 19 Oct 2016 12:18:49 +0200 Subject: [PATCH 108/133] fixes for service and workerRunner --- .../Component/Worker/Service/Service.php | 10 ++- .../Worker/Service/ServiceSupport.php | 73 +++++++++++-------- src/SAREhub/Component/Worker/WorkerRunner.php | 35 ++------- .../Worker/Service/ServiceSupportTest.php | 22 +++++- .../Component/Worker/WorkerRunnerTest.php | 5 ++ 5 files changed, 85 insertions(+), 60 deletions(-) diff --git a/src/SAREhub/Component/Worker/Service/Service.php b/src/SAREhub/Component/Worker/Service/Service.php index 2465180..5221465 100644 --- a/src/SAREhub/Component/Worker/Service/Service.php +++ b/src/SAREhub/Component/Worker/Service/Service.php @@ -2,7 +2,10 @@ namespace SAREhub\Component\Worker\Service; -interface Service { +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerInterface; + +interface Service extends LoggerAwareInterface { /** * Executed for start service. @@ -36,4 +39,9 @@ public function isStopped(); * @return boolean */ public function isRunning(); + + /** + * @return LoggerInterface + */ + public function getLogger(); } \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Service/ServiceSupport.php b/src/SAREhub/Component/Worker/Service/ServiceSupport.php index 5c6db7b..355776f 100644 --- a/src/SAREhub/Component/Worker/Service/ServiceSupport.php +++ b/src/SAREhub/Component/Worker/Service/ServiceSupport.php @@ -2,11 +2,10 @@ namespace SAREhub\Component\Worker\Service; -use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; -abstract class ServiceSupport implements Service, LoggerAwareInterface { +abstract class ServiceSupport implements Service { /** * @var LoggerInterface @@ -21,57 +20,53 @@ abstract class ServiceSupport implements Service, LoggerAwareInterface { * @throws \Exception When something was wrong. */ public function start() { - if (!$this->isStarted()) { - $this->getLogger()->info('service starting ...'); - $this->doStart(); - $this->started = true; - $this->stopped = false; - $this->getLogger()->info('service started'); + try { + if (!$this->isStarted()) { + $this->getLogger()->info('service starting ...'); + $this->doStart(); + $this->started = true; + $this->stopped = false; + $this->getLogger()->info('service started'); + } + } catch (\Exception $e) { + $this->getLogger()->error($e); } } - /** - * Contains custom worker start logic - * @throws \Exception When something was wrong. - */ - protected abstract function doStart(); - /** * Executed on every service tick. * @throws \Exception When something was wrong. */ public function tick() { - if ($this->isRunning()) { - $this->doTick(); + try { + if ($this->isRunning()) { + $this->doTick(); + } + } catch (\Exception $e) { + $this->getLogger()->error($e); + $this->stop(); } } - /** - * Contains custom worker tick logic - * @throws \Exception When something was wrong. - */ - protected abstract function doTick(); - /** * Executed for stop service * @throws \Exception When something was wrong. */ public function stop() { if ($this->isStarted()) { - $this->getLogger()->info('service stopping ...'); - $this->doStop(); + try { + $this->getLogger()->info('service stopping ...'); + $this->doStop(); + } catch (\Exception $e) { + $this->getLogger()->error($e); + } + $this->started = false; $this->stopped = true; $this->getLogger()->info('service stopped'); } } - /** - * Contains custom worker stop logic - * @throws \Exception When something was wrong. - */ - protected abstract function doStop(); - /** * @return boolean */ @@ -111,4 +106,22 @@ public function setLogger(LoggerInterface $logger) { } $this->logger = $logger; } + + /** + * Contains custom worker start logic + * @throws \Exception When something was wrong. + */ + protected abstract function doStart(); + + /** + * Contains custom worker tick logic + * @throws \Exception When something was wrong. + */ + protected abstract function doTick(); + + /** + * Contains custom worker stop logic + * @throws \Exception When something was wrong. + */ + protected abstract function doStop(); } \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/WorkerRunner.php b/src/SAREhub/Component/Worker/WorkerRunner.php index 1d24170..8c5e3e8 100644 --- a/src/SAREhub/Component/Worker/WorkerRunner.php +++ b/src/SAREhub/Component/Worker/WorkerRunner.php @@ -87,30 +87,13 @@ public function usePcntl(PcntlSignals $signals = null, $install = true) { return $this; } - /** - * Contains custom worker start logic - * @throws \Exception When something was wrong. - */ protected function doStart() { - try { - $this->getWorker()->start(); - } catch (\Exception $e) { - $this->getLogger()->error($e); - } + $this->getWorker()->start(); } - /** - * Contains custom worker tick logic - * @throws \Exception When something was wrong. - */ protected function doTick() { - try { - $this->checkCommand(); - $this->getWorker()->tick(); - } catch (\Exception $e) { - $this->getLogger()->error($e); - } - + $this->checkCommand(); + $this->getWorker()->tick(); $this->getPcntlSignals()->checkPendingSignals(); } @@ -163,20 +146,16 @@ private function onProcessCommandException(Command $command, \Exception $e, call * @throws \Exception When something was wrong. */ protected function doStop() { - try { - $this->getWorker()->stop(); - $this->getCommandInput()->close(); - $this->getCommandReplyOutput()->close(); - } catch (\Exception $e) { - $this->getLogger()->error($e); - } + $this->getWorker()->stop(); + $this->getCommandInput()->close(); + $this->getCommandReplyOutput()->close(); } /** * @return bool */ public function isRunning() { - return !$this->getWorker()->isStopped(); + return !$this->getWorker()->isStopped() && !$this->isStopped(); } /** diff --git a/tests/unit/SAREhub/Component/Worker/Service/ServiceSupportTest.php b/tests/unit/SAREhub/Component/Worker/Service/ServiceSupportTest.php index 6272eea..b7564f0 100644 --- a/tests/unit/SAREhub/Component/Worker/Service/ServiceSupportTest.php +++ b/tests/unit/SAREhub/Component/Worker/Service/ServiceSupportTest.php @@ -13,7 +13,7 @@ protected function doStart() { protected function doTick() { - + echo "test"; } @@ -119,6 +119,26 @@ public function testSetLoggerWhenSetsAndSetSameThenException() { $this->service->setLogger($logger); } + public function testStartWhenDoStartThrowExceptionThenNotStarted() { + $this->service->method('doStart')->willThrowException(new Exception('e')); + $this->service->start(); + $this->assertFalse($this->service->isStarted()); + } + + public function testStopWhenDoStopThrowExceptionThenStopped() { + $this->service->start(); + $this->service->method('doStop')->willThrowException(new Exception('e')); + $this->service->stop(); + $this->assertTrue($this->service->isStopped()); + } + + public function testTickWhenDoTickThrowExceptionThenStopped() { + $this->service->start(); + $this->service->method('doTick')->willThrowException(new Exception('exception')); + $this->service->tick(); + $this->assertFalse($this->service->isRunning()); + } + private function getMethodSpy($method) { $this->service->expects($methodSpy = $this->any())->method($method); return $methodSpy; diff --git a/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php b/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php index 3e2ce83..47b5a8d 100644 --- a/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php +++ b/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php @@ -28,6 +28,7 @@ public function testStart() { } public function testTick() { + $this->workerRunner->start(); $this->workerMock->expects($this->once())->method('tick'); $this->workerRunner->tick(); } @@ -41,6 +42,7 @@ public function testStopWhenStarted() { } public function testTickWhenCommandThenWorkerProcessCommand() { + $this->workerRunner->start(); $command = new BasicCommand('1', 'test'); $this->commandInputMock->expects($this->once())->method('getNext')->willReturn($command); $this->workerMock->expects($this->once())->method('processCommand') @@ -50,12 +52,14 @@ public function testTickWhenCommandThenWorkerProcessCommand() { } public function testTickWhenNoCommandThenWorkerNotProcessCommand() { + $this->workerRunner->start(); $this->commandInputMock->expects($this->once())->method('getNext')->willReturn(null); $this->workerMock->expects($this->never())->method('processCommand'); $this->workerRunner->tick(); } public function testTickWhenProcessCommandException() { + $this->workerRunner->start(); $command = new BasicCommand('1', 'c'); $this->commandInputMock->expects($this->once())->method('getNext')->willReturn($command); $this->workerMock->method('processCommand')->willThrowException(new \Exception('m')); @@ -67,6 +71,7 @@ public function testTickWhenProcessCommandException() { } public function testTickThenCheckPendingSignals() { + $this->workerRunner->start(); echo extension_loaded('pcntl'); $signals = $this->createMock(PcntlSignals::class); $signals->expects($this->once())->method('checkPendingSignals'); From 049b174150e22b6f5d98f613a4190d4d57fc38d5 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Wed, 19 Oct 2016 14:33:22 +0200 Subject: [PATCH 109/133] added start-manager command to cli --- .../Worker/Cli/StartManagerCommand.php | 77 ++++++++++++++++ .../Worker/Cli/StartManagerCommandTest.php | 92 +++++++++++++++++++ 2 files changed, 169 insertions(+) create mode 100644 src/SAREhub/Component/Worker/Cli/StartManagerCommand.php create mode 100644 tests/unit/SAREhub/Component/Worker/Cli/StartManagerCommandTest.php diff --git a/src/SAREhub/Component/Worker/Cli/StartManagerCommand.php b/src/SAREhub/Component/Worker/Cli/StartManagerCommand.php new file mode 100644 index 0000000..f2b28ab --- /dev/null +++ b/src/SAREhub/Component/Worker/Cli/StartManagerCommand.php @@ -0,0 +1,77 @@ +systemdHelper = $helper; + return $this; + } + + protected function configure() { + $this->setName('start-manager') + ->setDescription('Starts new worker manager with selected config') + ->setHelp("Starts worker manager with config from file. Check example config: cli/workerManagerConfigExample.php ") + ->setDefinition(new InputDefinition([ + new InputOption('config', 'c', InputOption::VALUE_REQUIRED, 'path to manager config file') + ])); + } + + protected function execute(InputInterface $input, OutputInterface $output) { + $configFile = $input->getOption('config'); + $configPath = $this->getConfigPath($configFile); + if ($this->isConfigExists($configPath)) { + $this->getLogger()->info('starting manager with config ', ['config' => $configPath]); + $output->writeln('starting manager with config: '.$configPath); + + $unitName = $this->getManagerUnitInstanceName($configFile); + $this->getLogger()->info('manager unit instance name: ', ['unit' => $unitName]); + $output->writeln('manager instance unit name: '.$unitName); + + $return = $this->systemdHelper->start($unitName); + $this->getLogger()->info('systemd start output: '.$return); + $output->writeln('systemd start output: '.$return); + + } else { + $output->writeln("config file isn't exists"); + $this->getLogger()->warning("config file isn't exists", ['config' => $configPath]); + } + } + + private function getConfigPath($configFile) { + $configRootPath = $this->getCliConfig()->getRequiredAsMap('manager')->getRequired('configRootPath'); + return $configRootPath.'/'.$configFile; + } + + private function isConfigExists($configPath) { + return file_exists($configPath); + } + + private function getManagerUnitInstanceName($configFile) { + $escappedFile = $this->systemdHelper->escape($configFile); + return 'worker-manager@'.$escappedFile; + } +} \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Cli/StartManagerCommandTest.php b/tests/unit/SAREhub/Component/Worker/Cli/StartManagerCommandTest.php new file mode 100644 index 0000000..8932be1 --- /dev/null +++ b/tests/unit/SAREhub/Component/Worker/Cli/StartManagerCommandTest.php @@ -0,0 +1,92 @@ +vfsRoot = vfsStream::setup('root'); + $this->cli = $this->createMock(Cli::class); + $this->cli->method('getConfig')->willReturn(new Parameters([ + 'manager' => [ + 'configRootPath' => $this->vfsRoot->url() + ] + ])); + $this->systemdHelper = $this->createMock(SystemdHelper::class); + $application = new Application(); + $application->add(StartManagerCommand::newInstance() + ->withCli($this->cli) + ->withSystemdHelper($this->systemdHelper)); + + $this->commandTester = new CommandTester($application->find('start-manager')); + } + + public function testExecuteWhenConfigFileNotExistsThenPrint() { + $this->commandTester->execute(['-c' => 'file']); + $output = $this->commandTester->getDisplay(); + $this->assertContains("config file isn't exists", $output); + } + + public function testExecuteWhenNoConfigThenSystemdStartNotCall() { + $this->systemdHelper->expects($this->never())->method('start'); + $this->commandTester->execute(['-c' => 'file']); + } + + public function testExecuteWhenConfigThenSystemdStart() { + $this->vfsRoot->addChild(vfsStream::newFile('config.php')); + $this->systemdHelper->method('escape')->willReturn('escapped'); + $this->systemdHelper->expects($this->once())->method('start')->with('worker-manager@escapped'); + $this->commandTester->execute(['-c' => 'config.php']); + } + + public function testExecuteWhenConfigThenCallSystemdEscape() { + $this->vfsRoot->addChild(vfsStream::newFile('config.php')); + $this->systemdHelper->expects($this->once())->method('escape') + ->with('config.php'); + $this->commandTester->execute(['-c' => 'config.php']); + } + + public function testExecuteWhenConfigThenOutputStarting() { + $this->vfsRoot->addChild(vfsStream::newFile('config.php')); + $this->commandTester->execute(['-c' => 'config.php']); + + $configPath = $this->vfsRoot->url().'/config.php'; + $output = $this->commandTester->getDisplay(); + $this->assertContains("starting manager with config: ".$configPath, $output); + } + + public function testExecuteWhenConfigThenOutputUnitInstanceName() { + $this->vfsRoot->addChild(vfsStream::newFile('config.php')); + $this->systemdHelper->method('escape')->willReturn('escapped'); + $this->commandTester->execute(['-c' => 'config.php']); + $output = $this->commandTester->getDisplay(); + $this->assertContains("manager instance unit name: worker-manager@escapped", $output); + } + + public function testExecuteWhenConfigThenOutputSystemdStart() { + $this->vfsRoot->addChild(vfsStream::newFile('config.php')); + $this->systemdHelper->method('start')->willReturn('systemd_start'); + $this->commandTester->execute(['-c' => 'config.php']); + $output = $this->commandTester->getDisplay(); + $this->assertContains("systemd start output: systemd_start", $output); + } +} From 74c88ee90a2d8fae4b146db4ffbc7aaaa7843acf Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Wed, 19 Oct 2016 14:33:35 +0200 Subject: [PATCH 110/133] refactored --- .../Worker/Cli/{CliBootstrap.php => Cli.php} | 4 +- .../Component/Worker/Cli/CliCommand.php | 62 +++++++++++++++++++ .../Cli/{CliBootstrapTest.php => CliTest.php} | 8 +-- 3 files changed, 68 insertions(+), 6 deletions(-) rename src/SAREhub/Component/Worker/Cli/{CliBootstrap.php => Cli.php} (97%) create mode 100644 src/SAREhub/Component/Worker/Cli/CliCommand.php rename tests/unit/SAREhub/Component/Worker/Cli/{CliBootstrapTest.php => CliTest.php} (85%) diff --git a/src/SAREhub/Component/Worker/Cli/CliBootstrap.php b/src/SAREhub/Component/Worker/Cli/Cli.php similarity index 97% rename from src/SAREhub/Component/Worker/Cli/CliBootstrap.php rename to src/SAREhub/Component/Worker/Cli/Cli.php index 1321517..0c9cf09 100644 --- a/src/SAREhub/Component/Worker/Cli/CliBootstrap.php +++ b/src/SAREhub/Component/Worker/Cli/Cli.php @@ -6,7 +6,7 @@ use SAREhub\Component\Worker\Command\CommandService; use Symfony\Component\Console\Application; -class CliBootstrap { +class Cli { /** * @var Application @@ -75,7 +75,7 @@ public function run() { } public function registerCommand(CliCommand $command) { - $command->withBootstrap($this); + $command->withCli($this); $this->getApplication()->add($command); return $this; diff --git a/src/SAREhub/Component/Worker/Cli/CliCommand.php b/src/SAREhub/Component/Worker/Cli/CliCommand.php new file mode 100644 index 0000000..09877f5 --- /dev/null +++ b/src/SAREhub/Component/Worker/Cli/CliCommand.php @@ -0,0 +1,62 @@ +logger = new NullLogger(); + } + + /** + * @param Cli $cli + * @return $this + */ + public function withCli(Cli $cli) { + $this->cli = $cli; + return $this; + } + + /** + * @return Cli + */ + public function getCli() { + return $this->cli; + } + + /** + * @return Parameters + */ + public function getCliConfig() { + return $this->getCli()->getConfig(); + } + + /** + * @return LoggerInterface + */ + public function getLogger() { + return $this->logger; + } + + public function setLogger(LoggerInterface $logger) { + $this->logger = $logger; + } +} \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Cli/CliBootstrapTest.php b/tests/unit/SAREhub/Component/Worker/Cli/CliTest.php similarity index 85% rename from tests/unit/SAREhub/Component/Worker/Cli/CliBootstrapTest.php rename to tests/unit/SAREhub/Component/Worker/Cli/CliTest.php index 4287059..a8be439 100644 --- a/tests/unit/SAREhub/Component/Worker/Cli/CliBootstrapTest.php +++ b/tests/unit/SAREhub/Component/Worker/Cli/CliTest.php @@ -1,17 +1,17 @@ application = $this->createMock(Application::class); $this->commandService = $this->createMock(CommandService::class); - $this->bootstrap = CliBootstrap::newInstance() + $this->bootstrap = Cli::newInstance() ->withApplication($this->application) ->withCommandService($this->commandService); } From f589c38f334e256efdfe9c9eb01d8a2d8289b72f Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Wed, 19 Oct 2016 16:33:59 +0200 Subject: [PATCH 111/133] added SIGTERM handle --- src/SAREhub/Component/Worker/WorkerRunner.php | 1 + .../SAREhub/Component/Worker/WorkerRunnerTest.php | 13 +++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/SAREhub/Component/Worker/WorkerRunner.php b/src/SAREhub/Component/Worker/WorkerRunner.php index 8c5e3e8..10e0205 100644 --- a/src/SAREhub/Component/Worker/WorkerRunner.php +++ b/src/SAREhub/Component/Worker/WorkerRunner.php @@ -81,6 +81,7 @@ public function withCommandReplyOutput(CommandReplyOutput $output) { public function usePcntl(PcntlSignals $signals = null, $install = true) { $this->signals = ($signals) ? $signals : PcntlSignals::getGlobal(); $this->signals->handle(PcntlSignals::SIGINT, array($this, 'stop')); + $this->signals->handle(PcntlSignals::SIGTERM, array($this, 'stop')); if ($install) { $this->signals->install(); } diff --git a/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php b/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php index 47b5a8d..504d63c 100644 --- a/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php +++ b/tests/unit/SAREhub/Component/Worker/WorkerRunnerTest.php @@ -79,13 +79,18 @@ public function testTickThenCheckPendingSignals() { $this->workerRunner->tick(); } - public function testUsePcntlThenHandleSIGINT() { + public function testUsePcntlThenHandleSIGINT_AND_SIGTERM() { $runner = $this->workerRunner; $signals = $this->createMock(PcntlSignals::class); - $signals->expects($this->once())->method('handle') - ->with(PcntlSignals::SIGINT, $this->callback(function (array $callback) use ($runner) { + $signals->expects($this->atLeast(2))->method('handle') + ->withConsecutive([ + PcntlSignals::SIGINT, $this->callback(function (array $callback) use ($runner) { return $callback[0] === $runner && $callback[1] === 'stop'; - })); + })], [ + PcntlSignals::SIGTERM, $this->callback(function (array $callback) use ($runner) { + return $callback[0] === $runner && $callback[1] === 'stop'; + }) + ]); $runner->usePcntl($signals); } From 6351387075b1c8dbee0d0f10c283d76aba513901 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Wed, 19 Oct 2016 16:56:10 +0200 Subject: [PATCH 112/133] cli --- cli/config.php | 18 ++ cli/managers/test.php | 41 ++++ cli/test_worker/testWorkerRunner.php | 76 +++++++ cli/worker-cli | 47 +++++ cli/worker-manager@.service | 7 + cli/workerManagerConfigExample.php | 42 ++++ cli/workerManagerRunner.php | 41 ++++ composer.json | 1 + src/SAREhub/Component/Worker/Cli/Cli.php | 15 ++ .../Worker/Cli/StartManagerCommand.php | 17 +- .../Worker/Manager/WorkerManagerBootstrap.php | 190 ++++++++++++++++++ .../Worker/Cli/StartManagerCommandTest.php | 35 ++-- worker-cli | 32 --- 13 files changed, 499 insertions(+), 63 deletions(-) create mode 100644 cli/config.php create mode 100644 cli/managers/test.php create mode 100644 cli/test_worker/testWorkerRunner.php create mode 100644 cli/worker-cli create mode 100644 cli/worker-manager@.service create mode 100644 cli/workerManagerConfigExample.php create mode 100644 cli/workerManagerRunner.php create mode 100644 src/SAREhub/Component/Worker/Manager/WorkerManagerBootstrap.php delete mode 100644 worker-cli diff --git a/cli/config.php b/cli/config.php new file mode 100644 index 0000000..d324033 --- /dev/null +++ b/cli/config.php @@ -0,0 +1,18 @@ + [ + 'configRootPath' => __DIR__.'/managers' + ], + 'commandService' => [ + 'commandOutput' => [ + 'endpoint' => Dsn::tcp()->endpoint('127.0.0.1:40001') + ], + 'commandReplyInput' => [ + 'topic' => 'worker-cli', + 'endpoint' => Dsn::tcp()->endpoint('127.0.0.1:40002') + ] + ] +]; \ No newline at end of file diff --git a/cli/managers/test.php b/cli/managers/test.php new file mode 100644 index 0000000..dd53213 --- /dev/null +++ b/cli/managers/test.php @@ -0,0 +1,41 @@ + 'test', + 'manager' => [ + 'processService' => [ + 'runnerScript' => dirname(__DIR__).'/test_worker/testWorkerRunner.php', + 'arguments' => [], + 'workingDirectory' => './' + ], + 'commandService' => [ + 'commandOutput' => [ + 'endpoint' => Dsn::tcp()->endpoint('127.0.0.1:40003') + ], + 'commandReplyInput' => [ + 'topic' => 'worker.command.reply', + 'endpoint' => Dsn::tcp()->endpoint('127.0.0.1:40004') + ] + ], + + ], + 'runner' => [ + 'commandInput' => [ + 'topic' => 'example', + 'endpoint' => Dsn::tcp()->endpoint('127.0.0.1:40001') + ], + 'commandReplyOutput' => [ + 'topic' => 'example', + 'endpoint' => Dsn::tcp()->endpoint('127.0.0.1:40002') + ], + ], + 'logger' => [ + 'handlers' => [ + new StreamHandler(dirname(__DIR__).'/test_worker/managerLog', Logger::DEBUG) + ] + ] +]; \ No newline at end of file diff --git a/cli/test_worker/testWorkerRunner.php b/cli/test_worker/testWorkerRunner.php new file mode 100644 index 0000000..7b6fdb4 --- /dev/null +++ b/cli/test_worker/testWorkerRunner.php @@ -0,0 +1,76 @@ +logInfo('doStart'); + } + + protected function doTick() { + $this->logInfo('doTick'); + sleep(1); // hard work simulation + } + + protected function doStop() { + $this->logInfo('doStop'); + } + + protected function doCommand(Command $command, callable $replyCallback) { + $this->logInfo('doCommand: '.$command); + } + + private function logInfo($message) { + $this->getLogger()->info(sprintf($message, $this->getId())); + } +} + +$context = WorkerContext::newInstance() + ->withId($argv[1]) + ->withRootPath(__DIR__); + +$logHandler = new StreamHandler(__DIR__.'/log', Logger::DEBUG); +$logger = new Logger('test_worker_'.$context->getId(), [$logHandler]); +try { + $zmqContext = new ZMQContext(); + $runner = WorkerRunner::newInstance() + ->withWorker(new TestWorker($context)) + ->withCommandInput(ZmqCommandInput::newInstance() + ->withCommandSubscriber(Subscriber::inContext($zmqContext) + ->subscribe($context->getId()) + ->connect(Dsn::tcp()->endpoint('127.0.0.1:40003')) + ) + ->withCommandFormat(JsonCommandFormat::newInstance())) + ->withCommandReplyOutput(ZmqCommandReplyOutput::newInstance() + ->withPublisher(Publisher::inContext($zmqContext) + ->connect(Dsn::tcp()->endpoint('127.0.0.1:40004'))) + ->withPublishTopic('worker.command.reply') + )->usePcntl(); + + $runner->getWorker()->setLogger($logger); + $runner->setLogger(new Logger($logger->getName().'_runner', [$logHandler])); + $runner->start(); + while ($runner->isRunning()) { + $runner->tick(); + } + $runner->stop(); + +} catch (Exception $e) { + $logger->error($e); +} \ No newline at end of file diff --git a/cli/worker-cli b/cli/worker-cli new file mode 100644 index 0000000..fc57f83 --- /dev/null +++ b/cli/worker-cli @@ -0,0 +1,47 @@ +#!/usr/bin/env php +getRequiredAsMap('commandService'); + +$zmqContext = new ZMQContext(); +$sessionId = uniqid(mt_rand(10000, 100000).time()); + +$handlers = [new StreamHandler(__DIR__.'/cliLog')]; + +Cli::newInstance() + ->withApplication(new Application('Worker CLI', '0.1')) + ->withConfig($config) + ->withSessionId($sessionId) + ->withLoggerFactory(function ($name) use ($handlers) { + return new Logger($name, $handlers); + }) + ->withCommandService( + CommandService::newInstance() + ->withCommandOutput(ZmqCommandOutput::newInstance() + ->withPublisher(Publisher::inContext($zmqContext) + ->bind($commandServiceConfig->getRequiredAsMap('commandOutput')->getRequired('endpoint'))) + )->withCommandReplyInput(ZmqCommandReplyInput::newInstance() + ->withSubscriber(Subscriber::inContext($zmqContext) + ->bind($commandServiceConfig->getRequiredAsMap('commandReplyInput')->getRequired('endpoint')) + ->subscribe($commandServiceConfig->getRequiredAsMap('commandReplyInput')->getRequired('topic')) + ) + ) + )->registerCommand(StartManagerCommand::newInstance()->withSystemdHelper(new SystemdHelper())) + ->run(); + diff --git a/cli/worker-manager@.service b/cli/worker-manager@.service new file mode 100644 index 0000000..e4aaa32 --- /dev/null +++ b/cli/worker-manager@.service @@ -0,0 +1,7 @@ +[Unit] +Description=Worker Manager generator unit from sarehub/component_worker +Documentation=http://packagist.org/packages/sarehub/component_worker + +[Service] +Environment="WORKERCLI_MANAGER_RUNNER=" +ExecStart=/usr/bin/php ${WORKERCLI_MANAGER_RUNNER} %I diff --git a/cli/workerManagerConfigExample.php b/cli/workerManagerConfigExample.php new file mode 100644 index 0000000..11c64f7 --- /dev/null +++ b/cli/workerManagerConfigExample.php @@ -0,0 +1,42 @@ + '', + 'manager' => [ + 'processService' => [ + 'runnerScript' => '', + 'arguments' => [], + 'workingDirectory' => '' + ], + 'commandService' => [ + 'commandOutput' => [ + 'endpoint' => '' + ], + 'commandReplyInput' => [ + 'topic' => 'worker.command.reply', + 'endpoint' => '' + ] + ], + + ], + 'runner' => [ + 'commandInput' => [ + 'topic' => '', + 'endpoint' => '' + ], + 'commandReplyOutput' => [ + 'topic' => '', + 'endpoint' => '' + ], + ], + 'logger' => [ + 'handlers' => [ + [ + new StreamHandler('', Logger::INFO) + ] + ] + ] +]; \ No newline at end of file diff --git a/cli/workerManagerRunner.php b/cli/workerManagerRunner.php new file mode 100644 index 0000000..aa7b889 --- /dev/null +++ b/cli/workerManagerRunner.php @@ -0,0 +1,41 @@ +getRequiredAsMap('manager'); +$managerId = $argv[1]; +echo "starting manager with id: ".$managerId; + +$configFile = $managerId.'.php'; +echo "Config file: ".$configFile."\n"; +$configPath = $cliManagerConfig->getRequired('configRootPath').'/'.$configFile; +echo "Config file path: ".$configPath."\n"; + +if (file_exists($configPath)) { + echo "loading config\n"; + $config = include($configPath); + echo "config loaded\n"; + $runner = WorkerManagerBootstrap::newInstance() + ->withWorkerContex(WorkerContext::newInstance() + ->withId($config['id']) + ->withRootPath(getcwd()) + )->withConfig($config)->build(); + + $runner->start(); + while ($runner->isRunning()) { + $runner->tick(); + } + $runner->stop(); + + echo "stopped\n"; +} + + + + diff --git a/composer.json b/composer.json index f5e4c41..39deb66 100644 --- a/composer.json +++ b/composer.json @@ -11,6 +11,7 @@ ], "require-dev": { "phpunit/phpunit": "5.*", + "mikey179/vfsStream": "1.6.*", "codeclimate/php-test-reporter": "dev-master", "fig-r/psr2r-sniffer": "0.*", "phpdocumentor/phpdocumentor": "2.9.*" diff --git a/src/SAREhub/Component/Worker/Cli/Cli.php b/src/SAREhub/Component/Worker/Cli/Cli.php index 0c9cf09..00f068c 100644 --- a/src/SAREhub/Component/Worker/Cli/Cli.php +++ b/src/SAREhub/Component/Worker/Cli/Cli.php @@ -27,6 +27,7 @@ class Cli { * @var Parameters */ private $config; + private $loggerFactory; public static function newInstance() { return new self(); @@ -68,6 +69,15 @@ public function withConfig(Parameters $config) { return $this; } + /** + * @param callable $factory + * @return $this + */ + public function withLoggerFactory(callable $factory) { + $this->loggerFactory = $factory; + return $this; + } + public function run() { $this->getCommandService()->start(); $this->getApplication()->run(); @@ -76,11 +86,16 @@ public function run() { public function registerCommand(CliCommand $command) { $command->withCli($this); + $command->setLogger($this->getCommandLogger($command)); $this->getApplication()->add($command); return $this; } + private function getCommandLogger(CliCommand $command) { + return ($this->loggerFactory)($command->getName()); + } + /** * @return Application */ diff --git a/src/SAREhub/Component/Worker/Cli/StartManagerCommand.php b/src/SAREhub/Component/Worker/Cli/StartManagerCommand.php index f2b28ab..578d4a0 100644 --- a/src/SAREhub/Component/Worker/Cli/StartManagerCommand.php +++ b/src/SAREhub/Component/Worker/Cli/StartManagerCommand.php @@ -33,21 +33,21 @@ public function withSystemdHelper(SystemdHelper $helper) { protected function configure() { $this->setName('start-manager') - ->setDescription('Starts new worker manager with selected config') + ->setDescription('Starts selected worker manager') ->setHelp("Starts worker manager with config from file. Check example config: cli/workerManagerConfigExample.php ") ->setDefinition(new InputDefinition([ - new InputOption('config', 'c', InputOption::VALUE_REQUIRED, 'path to manager config file') + new InputOption('manager', 'm', InputOption::VALUE_REQUIRED, 'manager id') ])); } protected function execute(InputInterface $input, OutputInterface $output) { - $configFile = $input->getOption('config'); - $configPath = $this->getConfigPath($configFile); + $managerId = $input->getOption('manager'); + $configPath = $this->getConfigPath($managerId); if ($this->isConfigExists($configPath)) { $this->getLogger()->info('starting manager with config ', ['config' => $configPath]); $output->writeln('starting manager with config: '.$configPath); - $unitName = $this->getManagerUnitInstanceName($configFile); + $unitName = $this->getManagerUnitInstanceName($managerId); $this->getLogger()->info('manager unit instance name: ', ['unit' => $unitName]); $output->writeln('manager instance unit name: '.$unitName); @@ -63,15 +63,14 @@ protected function execute(InputInterface $input, OutputInterface $output) { private function getConfigPath($configFile) { $configRootPath = $this->getCliConfig()->getRequiredAsMap('manager')->getRequired('configRootPath'); - return $configRootPath.'/'.$configFile; + return $configRootPath.'/'.$configFile.'.php'; } private function isConfigExists($configPath) { return file_exists($configPath); } - private function getManagerUnitInstanceName($configFile) { - $escappedFile = $this->systemdHelper->escape($configFile); - return 'worker-manager@'.$escappedFile; + private function getManagerUnitInstanceName($managerId) { + return 'worker-manager@'.$managerId.'.service'; } } \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Manager/WorkerManagerBootstrap.php b/src/SAREhub/Component/Worker/Manager/WorkerManagerBootstrap.php new file mode 100644 index 0000000..a34c037 --- /dev/null +++ b/src/SAREhub/Component/Worker/Manager/WorkerManagerBootstrap.php @@ -0,0 +1,190 @@ +zmqContext = new \ZMQContext(); + } + + public static function newInstance() { + return new self(); + } + + /** + * @param WorkerContext $context + * @return $this + */ + public function withWorkerContex(WorkerContext $context) { + $this->workerContext = $context; + return $this; + } + + /** + * @param array $config + * @return $this + */ + public function withConfig(array $config) { + $this->config = new Parameters($config); + return $this; + } + + /** + * @return WorkerRunner + */ + public function build() { + return $this->createRunner(); + } + + /** + * @return WorkerRunner + */ + private function createRunner() { + $runner = WorkerRunner::newInstance() + ->withWorker($this->createManager()) + ->withCommandInput($this->createRunnerCommandInput()) + ->withCommandReplyOutput($this->createRunnerCommandReplyOutput()) + ->usePcntl(); + $runner->setLogger($this->createLogger('runner')); + return $runner; + } + + /** + * @return CommandInput + */ + private function createRunnerCommandInput() { + $config = $this->getRunnerConfig()->getRequiredAsMap('commandInput'); + return ZmqCommandInput::newInstance() + ->withCommandSubscriber(Subscriber::inContext($this->zmqContext) + ->subscribe($config->getRequired('topic')) + ->connect($config->getRequired('endpoint')) + ); + } + + /** + * @return CommandReplyOutput + */ + private function createRunnerCommandReplyOutput() { + $config = $this->getRunnerConfig()->getRequiredAsMap('commandReplyOutput'); + return ZmqCommandReplyOutput::newInstance() + ->withPublishTopic($config->getRequired('topic')) + ->withPublisher(Publisher::inContext($this->zmqContext) + ->connect($config->getRequired('endpoint')) + ); + } + + /** + * @return WorkerManager + */ + private function createManager() { + $manager = WorkerManager::newInstanceWithContext($this->workerContext) + ->withProcessService($this->createManagerProcessService()) + ->withCommandService($this->createManagerCommandService()); + $manager->setLogger($this->createLogger('manager')); + return $manager; + } + + private function createManagerProcessService() { + $config = $this->getManagerConfig()->getRequiredAsMap('processService'); + return WorkerProcessService::newInstance() + ->withWorkerProcessFactory(WorkerProcessFactory::newInstance() + ->withRunnerScriptPath($config->getRequired('runnerScript')) + ->withArguments($config->getRequired('arguments')) + ->withWorkingDirectory($config->getRequired('workingDirectory')) + ); + } + + private function createManagerCommandService() { + return CommandService::newInstance() + ->withCommandOutput($this->createManagerCommandServiceCommandOutput()) + ->withCommandReplyInput($this->createManagerCommandServiceCommandReplyInput()); + } + + private function createManagerCommandServiceCommandOutput() { + $config = $this->getManagerConfig() + ->getRequiredAsMap('commandService') + ->getRequiredAsMap('commandOutput'); + return ZmqCommandOutput::newInstance() + ->withPublisher(Publisher::inContext($this->zmqContext) + ->bind($config->getRequired('endpoint')) + )->withCommandFormat(JsonCommandFormat::newInstance()); + } + + private function createManagerCommandServiceCommandReplyInput() { + $config = $this->getManagerConfig() + ->getRequiredAsMap('commandService') + ->getRequiredAsMap('commandReplyInput'); + + return ZmqCommandReplyInput::newInstance() + ->withSubscriber(Subscriber::inContext($this->zmqContext) + ->subscribe($config->getRequired('topic')) + ->bind($config->get('endpoint')) + ); + } + + private function createLogger($name) { + $config = $this->getLoggerConfig(); + $logger = new Logger($this->getConfig()->getRequired('id').'_'.$name); + foreach ($config->getRequired('handlers') as $handler) { + $logger->pushHandler($handler); + } + + return $logger; + } + + /** + * @return Parameters + */ + private function getManagerConfig() { + return $this->getConfig()->getRequiredAsMap('manager'); + } + + /** + * @return Parameters + */ + private function getRunnerConfig() { + return $this->getConfig()->getRequiredAsMap('runner'); + } + + /** + * @return Parameters + */ + private function getLoggerConfig() { + return $this->getConfig()->getRequiredAsMap('logger'); + } + + private function getConfig() { + return $this->config; + } +} \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Cli/StartManagerCommandTest.php b/tests/unit/SAREhub/Component/Worker/Cli/StartManagerCommandTest.php index 8932be1..5f298fb 100644 --- a/tests/unit/SAREhub/Component/Worker/Cli/StartManagerCommandTest.php +++ b/tests/unit/SAREhub/Component/Worker/Cli/StartManagerCommandTest.php @@ -41,51 +41,42 @@ protected function setUp() { } public function testExecuteWhenConfigFileNotExistsThenPrint() { - $this->commandTester->execute(['-c' => 'file']); + $this->commandTester->execute(['-m' => 'file']); $output = $this->commandTester->getDisplay(); $this->assertContains("config file isn't exists", $output); } public function testExecuteWhenNoConfigThenSystemdStartNotCall() { $this->systemdHelper->expects($this->never())->method('start'); - $this->commandTester->execute(['-c' => 'file']); + $this->commandTester->execute(['-m' => 'file']); } public function testExecuteWhenConfigThenSystemdStart() { - $this->vfsRoot->addChild(vfsStream::newFile('config.php')); - $this->systemdHelper->method('escape')->willReturn('escapped'); - $this->systemdHelper->expects($this->once())->method('start')->with('worker-manager@escapped'); - $this->commandTester->execute(['-c' => 'config.php']); - } - - public function testExecuteWhenConfigThenCallSystemdEscape() { - $this->vfsRoot->addChild(vfsStream::newFile('config.php')); - $this->systemdHelper->expects($this->once())->method('escape') - ->with('config.php'); - $this->commandTester->execute(['-c' => 'config.php']); + $this->vfsRoot->addChild(vfsStream::newFile('manager.php')); + $this->systemdHelper->expects($this->once())->method('start')->with('worker-manager@manager.service'); + $this->commandTester->execute(['-m' => 'manager']); } public function testExecuteWhenConfigThenOutputStarting() { - $this->vfsRoot->addChild(vfsStream::newFile('config.php')); - $this->commandTester->execute(['-c' => 'config.php']); + $this->vfsRoot->addChild(vfsStream::newFile('manager.php')); + $this->commandTester->execute(['-m' => 'manager']); - $configPath = $this->vfsRoot->url().'/config.php'; + $configPath = $this->vfsRoot->url().'/manager.php'; $output = $this->commandTester->getDisplay(); $this->assertContains("starting manager with config: ".$configPath, $output); } public function testExecuteWhenConfigThenOutputUnitInstanceName() { - $this->vfsRoot->addChild(vfsStream::newFile('config.php')); - $this->systemdHelper->method('escape')->willReturn('escapped'); - $this->commandTester->execute(['-c' => 'config.php']); + $this->vfsRoot->addChild(vfsStream::newFile('manager.php')); + $this->commandTester->execute(['-m' => 'manager']); $output = $this->commandTester->getDisplay(); - $this->assertContains("manager instance unit name: worker-manager@escapped", $output); + $this->assertContains("manager instance unit name: worker-manager@manager.service", $output); } public function testExecuteWhenConfigThenOutputSystemdStart() { - $this->vfsRoot->addChild(vfsStream::newFile('config.php')); + $this->vfsRoot->addChild(vfsStream::newFile('manager.php')); $this->systemdHelper->method('start')->willReturn('systemd_start'); - $this->commandTester->execute(['-c' => 'config.php']); + $this->commandTester->execute(['-m' => 'manager']); $output = $this->commandTester->getDisplay(); $this->assertContains("systemd start output: systemd_start", $output); } diff --git a/worker-cli b/worker-cli deleted file mode 100644 index 001997e..0000000 --- a/worker-cli +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env php -setName('app:create-users') - // the short description shown while running "php bin/console list" - ->setDescription('Creates new users.') - // the full command description shown when running the command with - // the "--help" option - ->setHelp("This command allows you to create users..."); - } - - protected function execute(InputInterface $input, OutputInterface $output) { - $output->writeln("test"); - } -} - -$application = new Application(); - -$application->add(new CreateUserCommand()); -$application->run(); From 4db289555492b78da81f1e7b902224ce7f03d8a7 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Thu, 20 Oct 2016 14:34:25 +0200 Subject: [PATCH 113/133] fixes --- cli/managers/test.php | 10 ++++++++-- cli/workerManagerRunner.php | 12 +++++++++++- examples/WorkerManager/workerScript.php | 2 +- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/cli/managers/test.php b/cli/managers/test.php index dd53213..4272dc1 100644 --- a/cli/managers/test.php +++ b/cli/managers/test.php @@ -3,6 +3,7 @@ use Monolog\Handler\StreamHandler; use Monolog\Logger; use SAREhub\Commons\Misc\Dsn; +use SAREhub\Component\Worker\Manager\ManagerCommands; return [ 'id' => 'test', @@ -21,15 +22,20 @@ 'endpoint' => Dsn::tcp()->endpoint('127.0.0.1:40004') ] ], + 'startCommands' => [ + ManagerCommands::start('1', '1'), + ManagerCommands::start('2', '2'), + ManagerCommands::start('3', '3'), + ] ], 'runner' => [ 'commandInput' => [ - 'topic' => 'example', + 'topic' => 'test', 'endpoint' => Dsn::tcp()->endpoint('127.0.0.1:40001') ], 'commandReplyOutput' => [ - 'topic' => 'example', + 'topic' => 'test', 'endpoint' => Dsn::tcp()->endpoint('127.0.0.1:40002') ], ], diff --git a/cli/workerManagerRunner.php b/cli/workerManagerRunner.php index aa7b889..b31fe00 100644 --- a/cli/workerManagerRunner.php +++ b/cli/workerManagerRunner.php @@ -22,12 +22,22 @@ $config = include($configPath); echo "config loaded\n"; $runner = WorkerManagerBootstrap::newInstance() - ->withWorkerContex(WorkerContext::newInstance() + ->withWorkerContext(WorkerContext::newInstance() ->withId($config['id']) ->withRootPath(getcwd()) )->withConfig($config)->build(); $runner->start(); + if ($runner->isRunning()) { + $config = new Parameters($config); + $startCommands = $config->getRequiredAsMap('manager')->getRequired('startCommands'); + foreach ($startCommands as $command) { + $runner->processCommand($command, function ($command, $reply) { + var_dump($command); + var_dump($reply); + }); + } + } while ($runner->isRunning()) { $runner->tick(); } diff --git a/examples/WorkerManager/workerScript.php b/examples/WorkerManager/workerScript.php index 91a8676..cc5ea6f 100644 --- a/examples/WorkerManager/workerScript.php +++ b/examples/WorkerManager/workerScript.php @@ -60,7 +60,7 @@ private function logInfo($message) { ->withPublisher(Publisher::inContext($zmqContext) ->connect(Dsn::tcp()->endpoint('127.0.0.1:30002'))) ->withPublishTopic('worker.command.reply') - ); + )->usePcntl(); $runner->getWorker()->setLogger($logger); $runner->setLogger($logger); From 33f2def1bce768dd79f7d9a7e4bc80abd8579ca4 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Thu, 20 Oct 2016 16:17:09 +0200 Subject: [PATCH 114/133] added sync command --- .../Worker/Command/CommandRequest.php | 17 ++++++ .../Worker/Command/CommandService.php | 57 ++++++++++++------- .../Worker/Cli/StartManagerCommandTest.php | 13 +++-- 3 files changed, 61 insertions(+), 26 deletions(-) diff --git a/src/SAREhub/Component/Worker/Command/CommandRequest.php b/src/SAREhub/Component/Worker/Command/CommandRequest.php index 55fdc68..3725b5a 100644 --- a/src/SAREhub/Component/Worker/Command/CommandRequest.php +++ b/src/SAREhub/Component/Worker/Command/CommandRequest.php @@ -31,6 +31,8 @@ class CommandRequest { */ private $replyCallback; + private $processAsync = true; + protected function __construct() { } @@ -78,6 +80,14 @@ public function withReplyCallback(callable $callback) { return $this; } + /** + * @return $this + */ + public function syncMode() { + $this->processAsync = false; + return $this; + } + public function markAsSent($now) { $this->sentTime = $now; } @@ -128,4 +138,11 @@ public function getReplyTimeout() { public function getReplyCallback() { return $this->replyCallback; } + + /** + * @return bool + */ + public function isAsync() { + return $this->processAsync; + } } \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Command/CommandService.php b/src/SAREhub/Component/Worker/Command/CommandService.php index e6f1d16..c5bb1da 100644 --- a/src/SAREhub/Component/Worker/Command/CommandService.php +++ b/src/SAREhub/Component/Worker/Command/CommandService.php @@ -56,32 +56,21 @@ public function process(CommandRequest $request) { try { $this->commandOutput->send($request->getTopic(), $request->getCommand(), false); $request->markAsSent(TimeProvider::get()->now()); - $this->pendingRequests[] = $request; + + $correlationId = $request->getCommand()->getCorrelationId(); + $this->pendingRequests[$correlationId] = $request; + if (!$request->isAsync()) { + while (isset($this->pendingRequests[$correlationId])) { + $this->doTick(); + } + } + } catch (\Exception $e) { $this->onRequestException($request, $e); } } - /** - * @return CommandRequest[] - */ - public function getPendingRequests() { - return $this->pendingRequests; - } - - /** - * @return CommandOutput - */ - public function getCommandOutput() { - return $this->commandOutput; - } - /** - * @return CommandReplyInput - */ - public function getCommandReplyInput() { - return $this->commandReplyInput; - } protected function doStart() { @@ -96,6 +85,7 @@ protected function doTick() { 'reply' => $reply ]); ($request->getReplyCallback())($request, $reply); + $this->removeRequest($request->getCommand()->getCorrelationId()); } $this->getLogger()->info('not exists correlated command for reply', ['reply' => $reply]); } @@ -116,6 +106,7 @@ private function onRequestException(CommandRequest $request, \Exception $excepti ['exceptionMessage' => $exception->getMessage()] ); ($request->getReplyCallback())($request, $reply); + } /** @@ -140,7 +131,33 @@ private function checkReplyTimeout() { 'reply timeout' ); ($request->getReplyCallback())($request, $reply); + $this->removeRequest($request->getCommand()->getCorrelationId()); } } } + + private function removeRequest($correlationId) { + unset($this->pendingRequests[$correlationId]); + } + + /** + * @return CommandRequest[] + */ + public function getPendingRequests() { + return $this->pendingRequests; + } + + /** + * @return CommandOutput + */ + public function getCommandOutput() { + return $this->commandOutput; + } + + /** + * @return CommandReplyInput + */ + public function getCommandReplyInput() { + return $this->commandReplyInput; + } } \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Cli/StartManagerCommandTest.php b/tests/unit/SAREhub/Component/Worker/Cli/StartManagerCommandTest.php index 5f298fb..41ddefa 100644 --- a/tests/unit/SAREhub/Component/Worker/Cli/StartManagerCommandTest.php +++ b/tests/unit/SAREhub/Component/Worker/Cli/StartManagerCommandTest.php @@ -41,25 +41,25 @@ protected function setUp() { } public function testExecuteWhenConfigFileNotExistsThenPrint() { - $this->commandTester->execute(['-m' => 'file']); + $this->commandTester->execute(['manager' => 'file']); $output = $this->commandTester->getDisplay(); $this->assertContains("config file isn't exists", $output); } public function testExecuteWhenNoConfigThenSystemdStartNotCall() { $this->systemdHelper->expects($this->never())->method('start'); - $this->commandTester->execute(['-m' => 'file']); + $this->commandTester->execute(['manager' => 'file']); } public function testExecuteWhenConfigThenSystemdStart() { $this->vfsRoot->addChild(vfsStream::newFile('manager.php')); $this->systemdHelper->expects($this->once())->method('start')->with('worker-manager@manager.service'); - $this->commandTester->execute(['-m' => 'manager']); + $this->commandTester->execute(['manager' => 'manager']); } public function testExecuteWhenConfigThenOutputStarting() { $this->vfsRoot->addChild(vfsStream::newFile('manager.php')); - $this->commandTester->execute(['-m' => 'manager']); + $this->commandTester->execute(['manager' => 'manager']); $configPath = $this->vfsRoot->url().'/manager.php'; $output = $this->commandTester->getDisplay(); @@ -68,7 +68,7 @@ public function testExecuteWhenConfigThenOutputStarting() { public function testExecuteWhenConfigThenOutputUnitInstanceName() { $this->vfsRoot->addChild(vfsStream::newFile('manager.php')); - $this->commandTester->execute(['-m' => 'manager']); + $this->commandTester->execute(['manager' => 'manager']); $output = $this->commandTester->getDisplay(); $this->assertContains("manager instance unit name: worker-manager@manager.service", $output); } @@ -76,8 +76,9 @@ public function testExecuteWhenConfigThenOutputUnitInstanceName() { public function testExecuteWhenConfigThenOutputSystemdStart() { $this->vfsRoot->addChild(vfsStream::newFile('manager.php')); $this->systemdHelper->method('start')->willReturn('systemd_start'); - $this->commandTester->execute(['-m' => 'manager']); + $this->commandTester->execute(['manager' => 'manager']); $output = $this->commandTester->getDisplay(); $this->assertContains("systemd start output: systemd_start", $output); } + } From 5c352336a235edbe59153f10c46fbd831f3e60fe Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Fri, 21 Oct 2016 14:58:42 +0200 Subject: [PATCH 115/133] fixes --- .../Worker/Cli/StartManagerCommand.php | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/SAREhub/Component/Worker/Cli/StartManagerCommand.php b/src/SAREhub/Component/Worker/Cli/StartManagerCommand.php index 578d4a0..65e4f7d 100644 --- a/src/SAREhub/Component/Worker/Cli/StartManagerCommand.php +++ b/src/SAREhub/Component/Worker/Cli/StartManagerCommand.php @@ -2,9 +2,8 @@ namespace SAREhub\Component\Worker\Cli; -use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class StartManagerCommand extends CliCommand { @@ -35,13 +34,11 @@ protected function configure() { $this->setName('start-manager') ->setDescription('Starts selected worker manager') ->setHelp("Starts worker manager with config from file. Check example config: cli/workerManagerConfigExample.php ") - ->setDefinition(new InputDefinition([ - new InputOption('manager', 'm', InputOption::VALUE_REQUIRED, 'manager id') - ])); + ->addArgument('manager', InputArgument::REQUIRED, 'manager id to start'); } protected function execute(InputInterface $input, OutputInterface $output) { - $managerId = $input->getOption('manager'); + $managerId = $input->getArgument('manager'); $configPath = $this->getConfigPath($managerId); if ($this->isConfigExists($configPath)) { $this->getLogger()->info('starting manager with config ', ['config' => $configPath]); @@ -49,12 +46,15 @@ protected function execute(InputInterface $input, OutputInterface $output) { $unitName = $this->getManagerUnitInstanceName($managerId); $this->getLogger()->info('manager unit instance name: ', ['unit' => $unitName]); - $output->writeln('manager instance unit name: '.$unitName); + $output->write('manager instance unit name: '.$unitName.' '); $return = $this->systemdHelper->start($unitName); - $this->getLogger()->info('systemd start output: '.$return); - $output->writeln('systemd start output: '.$return); - + if (!empty($return)) { + $this->getLogger()->info('systemd start output: '.$return); + $output->writeln('systemd start output: '.$return); + } else { + $output->writeln('started'); + } } else { $output->writeln("config file isn't exists"); $this->getLogger()->warning("config file isn't exists", ['config' => $configPath]); From ae223c36834495ffc8e885d5e835dc230c556226 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Fri, 21 Oct 2016 14:59:02 +0200 Subject: [PATCH 116/133] added start worker command to cli --- .../Worker/Cli/StartWorkerCommand.php | 41 ++++++++++ .../Worker/Cli/StartWorkerCommandTest.php | 79 +++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 src/SAREhub/Component/Worker/Cli/StartWorkerCommand.php create mode 100644 tests/unit/SAREhub/Component/Worker/Cli/StartWorkerCommandTest.php diff --git a/src/SAREhub/Component/Worker/Cli/StartWorkerCommand.php b/src/SAREhub/Component/Worker/Cli/StartWorkerCommand.php new file mode 100644 index 0000000..85ef986 --- /dev/null +++ b/src/SAREhub/Component/Worker/Cli/StartWorkerCommand.php @@ -0,0 +1,41 @@ +setName('start-worker') + ->setDescription('starts worker in selected manager') + ->addArgument('manager', InputArgument::REQUIRED, 'manager id') + ->addArgument('worker', InputArgument::REQUIRED, 'worker id'); + } + + protected function execute(InputInterface $input, OutputInterface $output) { + $managerId = $input->getArgument('manager'); + $workerId = $input->getArgument('worker'); + + $this->getCli()->getCommandService()->process( + CommandRequest::newInstance() + ->withTopic($managerId) + ->syncMode() + ->withCommand(ManagerCommands::start($this->getCli()->getSessionId(), $workerId)) + ->withReplyCallback(function (CommandRequest $request, CommandReply $reply) use ($output) { + $output->writeln('manager reply: '.$reply->toJson()); + }) + ); + } + +} \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Cli/StartWorkerCommandTest.php b/tests/unit/SAREhub/Component/Worker/Cli/StartWorkerCommandTest.php new file mode 100644 index 0000000..da779c6 --- /dev/null +++ b/tests/unit/SAREhub/Component/Worker/Cli/StartWorkerCommandTest.php @@ -0,0 +1,79 @@ +cli = $this->createMock(Cli::class); + $this->commandService = $this->createMock(CommandService::class); + + $this->cli->method('getCommandService')->willReturn($this->commandService); + $application = new Application(); + $application->add(StartWorkerCommand::newInstance() + ->withCli($this->cli)); + + $this->commandTester = new CommandTester($application->find('start-worker')); + } + + public function testExecuteThenCommandServiceProcess() { + $this->commandService->expects($this->once())->method('process'); + $this->commandTester->execute(['manager' => 'm', 'worker' => 'w']); + } + + public function testExecuteThenCommandRequestTopicIsManagerId() { + $this->assertCommandRequest(function (CommandRequest $request) { + return $request->getTopic() === 'm'; + }); + $this->commandTester->execute(['manager' => 'm', 'worker' => 'w']); + } + + public function testExecuteThenCommandRequestNotAsync() { + $this->assertCommandRequest(function (CommandRequest $request) { + return !$request->isAsync(); + }); + $this->commandTester->execute(['manager' => 'm', 'worker' => 'w']); + } + + public function testExecuteThenCommandRequestCommandManagerStartWorker() { + $this->assertCommandRequest(function (CommandRequest $request) { + return $request->getCommand()->getName() === ManagerCommands::START; + }); + $this->commandTester->execute(['manager' => 'm', 'worker' => 'w']); + } + + public function testExecuteWhenReplyThenCommandRequestReplyCallbackOutput() { + $reply = CommandReply::success('1', 'm'); + $this->assertCommandRequest(function (CommandRequest $request) use ($reply) { + ($request->getReplyCallback())($request, $reply); + return true; + }); + + $this->commandTester->execute(['manager' => 'm', 'worker' => 'w']); + $this->assertContains('manager reply: '.$reply->toJson(), $this->commandTester->getDisplay()); + + } + + private function assertCommandRequest(callable $callback) { + $this->commandService->expects($this->once())->method('process') + ->with($this->callback($callback)); + } +} From 53cf4f6a813fce0e56e2e2fec465a3d106273fd2 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Fri, 21 Oct 2016 14:59:26 +0200 Subject: [PATCH 117/133] fixes --- src/SAREhub/Component/Worker/WorkerRunner.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/SAREhub/Component/Worker/WorkerRunner.php b/src/SAREhub/Component/Worker/WorkerRunner.php index 10e0205..33fecd3 100644 --- a/src/SAREhub/Component/Worker/WorkerRunner.php +++ b/src/SAREhub/Component/Worker/WorkerRunner.php @@ -93,8 +93,10 @@ protected function doStart() { } protected function doTick() { - $this->checkCommand(); - $this->getWorker()->tick(); + if ($this->isRunning()) { + $this->checkCommand(); + $this->getWorker()->tick(); + } $this->getPcntlSignals()->checkPendingSignals(); } @@ -109,7 +111,7 @@ private function checkCommand() { } } - private function processCommand(Command $command, callable $replyCallback) { + public function processCommand(Command $command, callable $replyCallback) { $this->getLogger()->info('process command', ['command' => (string)$command]); try { $this->onCommand($command, $replyCallback); From f0fa932c0dd3b52e2d9b15417b9be3b503d0f9ca Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Fri, 21 Oct 2016 15:00:25 +0200 Subject: [PATCH 118/133] changed default timeout for command request from 30 to 10 --- src/SAREhub/Component/Worker/Command/CommandRequest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SAREhub/Component/Worker/Command/CommandRequest.php b/src/SAREhub/Component/Worker/Command/CommandRequest.php index 3725b5a..3e8b9be 100644 --- a/src/SAREhub/Component/Worker/Command/CommandRequest.php +++ b/src/SAREhub/Component/Worker/Command/CommandRequest.php @@ -4,7 +4,7 @@ class CommandRequest { - const DEFAULT_REPLY_TIMEOUT = 30; + const DEFAULT_REPLY_TIMEOUT = 10; /** * @var string From 00ffb09c3c542411d44ac7e42c10386885b0c06d Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Fri, 21 Oct 2016 15:01:32 +0200 Subject: [PATCH 119/133] fixes --- cli/managers/test.php | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/cli/managers/test.php b/cli/managers/test.php index 4272dc1..9caf096 100644 --- a/cli/managers/test.php +++ b/cli/managers/test.php @@ -27,17 +27,6 @@ ManagerCommands::start('2', '2'), ManagerCommands::start('3', '3'), ] - - ], - 'runner' => [ - 'commandInput' => [ - 'topic' => 'test', - 'endpoint' => Dsn::tcp()->endpoint('127.0.0.1:40001') - ], - 'commandReplyOutput' => [ - 'topic' => 'test', - 'endpoint' => Dsn::tcp()->endpoint('127.0.0.1:40002') - ], ], 'logger' => [ 'handlers' => [ From 0b996a84ebef8ee29eabfa248b2654fe556c443e Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Fri, 21 Oct 2016 15:02:21 +0200 Subject: [PATCH 120/133] fixes --- cli/config.php | 14 ++++++++++++-- cli/worker-cli | 8 ++++++-- cli/worker-manager@.service | 7 ++++++- cli/workerManagerRunner.php | 26 +++++++++++++++++++++++--- 4 files changed, 47 insertions(+), 8 deletions(-) diff --git a/cli/config.php b/cli/config.php index d324033..9a96f2b 100644 --- a/cli/config.php +++ b/cli/config.php @@ -4,7 +4,17 @@ return [ 'manager' => [ - 'configRootPath' => __DIR__.'/managers' + 'configRootPath' => __DIR__.'/managers', + 'forwarders' => [ + 'commandOutput' => [ + 'input' => Dsn::tcp()->endpoint('127.0.0.1:40001'), + 'output' => Dsn::tcp()->endpoint('127.0.0.1:40002') + ], + 'commandReplyInput' => [ + 'input' => Dsn::tcp()->endpoint('127.0.0.1:40005'), + 'output' => Dsn::tcp()->endpoint('127.0.0.1:40006') + ] + ], ], 'commandService' => [ 'commandOutput' => [ @@ -12,7 +22,7 @@ ], 'commandReplyInput' => [ 'topic' => 'worker-cli', - 'endpoint' => Dsn::tcp()->endpoint('127.0.0.1:40002') + 'endpoint' => Dsn::tcp()->endpoint('127.0.0.1:40006') ] ] ]; \ No newline at end of file diff --git a/cli/worker-cli b/cli/worker-cli index fc57f83..1fe3f5e 100644 --- a/cli/worker-cli +++ b/cli/worker-cli @@ -8,8 +8,10 @@ use SAREhub\Commons\Zmq\PublishSubscribe\Publisher; use SAREhub\Commons\Zmq\PublishSubscribe\Subscriber; use SAREhub\Component\Worker\Cli\Cli; use SAREhub\Component\Worker\Cli\StartManagerCommand; +use SAREhub\Component\Worker\Cli\StartWorkerCommand; use SAREhub\Component\Worker\Cli\SystemdHelper; use SAREhub\Component\Worker\Command\CommandService; +use SAREhub\Component\Worker\Command\JsonCommandFormat; use SAREhub\Component\Worker\Command\ZmqCommandOutput; use SAREhub\Component\Worker\Command\ZmqCommandReplyInput; use Symfony\Component\Console\Application; @@ -35,13 +37,15 @@ Cli::newInstance() CommandService::newInstance() ->withCommandOutput(ZmqCommandOutput::newInstance() ->withPublisher(Publisher::inContext($zmqContext) - ->bind($commandServiceConfig->getRequiredAsMap('commandOutput')->getRequired('endpoint'))) + ->connect($commandServiceConfig->getRequiredAsMap('commandOutput')->getRequired('endpoint'))) + ->withCommandFormat(JsonCommandFormat::newInstance()) )->withCommandReplyInput(ZmqCommandReplyInput::newInstance() ->withSubscriber(Subscriber::inContext($zmqContext) - ->bind($commandServiceConfig->getRequiredAsMap('commandReplyInput')->getRequired('endpoint')) + ->connect($commandServiceConfig->getRequiredAsMap('commandReplyInput')->getRequired('endpoint')) ->subscribe($commandServiceConfig->getRequiredAsMap('commandReplyInput')->getRequired('topic')) ) ) )->registerCommand(StartManagerCommand::newInstance()->withSystemdHelper(new SystemdHelper())) + ->registerCommand(StartWorkerCommand::newInstance()) ->run(); diff --git a/cli/worker-manager@.service b/cli/worker-manager@.service index e4aaa32..567aaee 100644 --- a/cli/worker-manager@.service +++ b/cli/worker-manager@.service @@ -3,5 +3,10 @@ Description=Worker Manager generator unit from sarehub/component_worker Documentation=http://packagist.org/packages/sarehub/component_worker [Service] -Environment="WORKERCLI_MANAGER_RUNNER=" +Environment="WORKERCLI_MANAGER_RUNNER=path_to_workerManagerRunner.php" ExecStart=/usr/bin/php ${WORKERCLI_MANAGER_RUNNER} %I + +TimeoutStopSec=60 +KillMode=process +KillSignal=SIGINT + diff --git a/cli/workerManagerRunner.php b/cli/workerManagerRunner.php index b31fe00..2b4e976 100644 --- a/cli/workerManagerRunner.php +++ b/cli/workerManagerRunner.php @@ -2,6 +2,8 @@ date_default_timezone_set('Europe/Warsaw'); use SAREhub\Commons\Misc\Parameters; +use SAREhub\Component\Worker\Command\Command; +use SAREhub\Component\Worker\Command\CommandReply; use SAREhub\Component\Worker\Manager\WorkerManagerBootstrap; use SAREhub\Component\Worker\WorkerContext; @@ -21,6 +23,24 @@ echo "loading config\n"; $config = include($configPath); echo "config loaded\n"; + $cliCommandServiceConfig = $cliConfig->getRequiredAsMap('manager')->getRequiredAsMap('forwarders'); + + $config['runner'] = [ + 'commandInput' => [ + 'topic' => '', + 'endpoint' => $cliCommandServiceConfig->getRequiredAsMap('commandOutput')->getRequired('output') + ], + 'commandReplyOutput' => [ + 'topic' => 'worker-cli', + 'endpoint' => $cliCommandServiceConfig->getRequiredAsMap('commandReplyInput')->getRequired('input') + ] + ]; + + echo 'listen command on '.$config['runner']['commandInput']['endpoint'] + .' with topic '.$config['runner']['commandInput']['topic']."\n"; + echo 'sending command reply on '.$config['runner']['commandReplyOutput']['endpoint'] + .' with topic '.$config['runner']['commandReplyOutput']['topic']."\n"; + $runner = WorkerManagerBootstrap::newInstance() ->withWorkerContext(WorkerContext::newInstance() ->withId($config['id']) @@ -32,9 +52,9 @@ $config = new Parameters($config); $startCommands = $config->getRequiredAsMap('manager')->getRequired('startCommands'); foreach ($startCommands as $command) { - $runner->processCommand($command, function ($command, $reply) { - var_dump($command); - var_dump($reply); + $runner->processCommand($command, function (Command $command, CommandReply $reply) { + echo $command."\n"; + echo $reply->toJson()."\n"; }); } } From 11fa2f635d5512e7f60df8976e02069ec1cfbcf6 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Fri, 21 Oct 2016 15:02:38 +0200 Subject: [PATCH 121/133] fixes --- .../Worker/Manager/WorkerManagerBootstrap.php | 4 +- .../Worker/Command/CommandServiceTest.php | 38 ++++++++++++++++++- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/SAREhub/Component/Worker/Manager/WorkerManagerBootstrap.php b/src/SAREhub/Component/Worker/Manager/WorkerManagerBootstrap.php index a34c037..79891f3 100644 --- a/src/SAREhub/Component/Worker/Manager/WorkerManagerBootstrap.php +++ b/src/SAREhub/Component/Worker/Manager/WorkerManagerBootstrap.php @@ -46,7 +46,7 @@ public static function newInstance() { * @param WorkerContext $context * @return $this */ - public function withWorkerContex(WorkerContext $context) { + public function withWorkerContext(WorkerContext $context) { $this->workerContext = $context; return $this; } @@ -89,7 +89,7 @@ private function createRunnerCommandInput() { ->withCommandSubscriber(Subscriber::inContext($this->zmqContext) ->subscribe($config->getRequired('topic')) ->connect($config->getRequired('endpoint')) - ); + )->withCommandFormat(JsonCommandFormat::newInstance()); } /** diff --git a/tests/unit/SAREhub/Component/Worker/Command/CommandServiceTest.php b/tests/unit/SAREhub/Component/Worker/Command/CommandServiceTest.php index 0df6cd8..2c36f27 100644 --- a/tests/unit/SAREhub/Component/Worker/Command/CommandServiceTest.php +++ b/tests/unit/SAREhub/Component/Worker/Command/CommandServiceTest.php @@ -75,7 +75,7 @@ public function testProcessThenRequestSentTimeIsNow() { public function testProcessThenPendingRequest() { $this->service->process($this->request); - $this->assertEquals([$this->request], $this->service->getPendingRequests()); + $this->assertEquals(['1' => $this->request], $this->service->getPendingRequests()); } public function testProcessWhenSendExceptionThenCallReplyCallbackWithErrorReply() { @@ -99,6 +99,21 @@ public function testProcessWhenSendExceptionThenNotSent() { $this->assertFalse($this->request->isSent()); } + public function testProcessWhenNotAsyncThenWaitForReply() { + $this->request->syncMode(); + $this->inputMock->expects($this->atLeast(2))->method('getNext') + ->willReturnOnConsecutiveCalls(null, CommandReply::success('1', 'm')); + $this->service->process($this->request); + } + + public function testProcessWhenNotAsyncThenWaitAndCallReplyCallback() { + $this->request->syncMode(); + $this->inputMock->method('getNext') + ->willReturnOnConsecutiveCalls(null, CommandReply::success('1', 'm')); + $this->request->getReplyCallback()->expects($this->once())->method('__invoke'); + $this->service->process($this->request); + } + public function testDoTickWhenReplyThenCallReplyCallback() { $this->service->process($this->request); $reply = CommandReply::success( @@ -136,6 +151,27 @@ public function testDoTickWhenRequestReplyTimeoutThenCallReplyCallbackWithErrorR $this->service->tick(); } + public function testTickWhenRequestReplyThenRemoveRequest() { + $this->service->process($this->request); + $reply = CommandReply::success( + $this->request->getCommand()->getCorrelationId(), + 'm' + ); + + $this->inputMock->method('getNext')->willReturn($reply); + $this->service->tick(); + $this->assertEquals([], $this->service->getPendingRequests()); + } + + public function testTickWhenRequestReplyTimeoutThenRemoveRequest() { + $now = time(); + TimeProvider::get()->freezeTime($now); + $this->service->process($this->request); + TimeProvider::get()->freezeTime($now + $this->request->getReplyTimeout()); + $this->service->tick(); + $this->assertEquals([], $this->service->getPendingRequests()); + } + public function testStopThenCommandOutputClose() { $this->outputMock->expects($this->once())->method('close'); $this->service->stop(); From e856f299e999ce2a63cd02b233194340bba13537 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Fri, 21 Oct 2016 15:26:27 +0200 Subject: [PATCH 122/133] added stop manager command to cli --- cli/worker-cli | 2 + .../Worker/Cli/StopManagerCommand.php | 38 +++++++++ .../Worker/Cli/StopManagerCommandTest.php | 78 +++++++++++++++++++ 3 files changed, 118 insertions(+) create mode 100644 src/SAREhub/Component/Worker/Cli/StopManagerCommand.php create mode 100644 tests/unit/SAREhub/Component/Worker/Cli/StopManagerCommandTest.php diff --git a/cli/worker-cli b/cli/worker-cli index 1fe3f5e..d364965 100644 --- a/cli/worker-cli +++ b/cli/worker-cli @@ -9,6 +9,7 @@ use SAREhub\Commons\Zmq\PublishSubscribe\Subscriber; use SAREhub\Component\Worker\Cli\Cli; use SAREhub\Component\Worker\Cli\StartManagerCommand; use SAREhub\Component\Worker\Cli\StartWorkerCommand; +use SAREhub\Component\Worker\Cli\StopManagerCommand; use SAREhub\Component\Worker\Cli\SystemdHelper; use SAREhub\Component\Worker\Command\CommandService; use SAREhub\Component\Worker\Command\JsonCommandFormat; @@ -47,5 +48,6 @@ Cli::newInstance() ) )->registerCommand(StartManagerCommand::newInstance()->withSystemdHelper(new SystemdHelper())) ->registerCommand(StartWorkerCommand::newInstance()) + ->registerCommand(StopManagerCommand::newInstance()) ->run(); diff --git a/src/SAREhub/Component/Worker/Cli/StopManagerCommand.php b/src/SAREhub/Component/Worker/Cli/StopManagerCommand.php new file mode 100644 index 0000000..240f06b --- /dev/null +++ b/src/SAREhub/Component/Worker/Cli/StopManagerCommand.php @@ -0,0 +1,38 @@ +setName('stop-manager') + ->setDescription('stops selected worker manager') + ->addArgument('manager', InputArgument::REQUIRED, 'manager id'); + } + + protected function execute(InputInterface $input, OutputInterface $output) { + $managerId = $input->getArgument('manager'); + $this->getCli()->getCommandService()->process( + CommandRequest::newInstance() + ->withTopic($managerId) + ->syncMode() + ->withCommand(WorkerCommands::stop($this->getCli()->getSessionId())) + ->withReplyCallback(function (CommandRequest $request, CommandReply $reply) use ($output) { + $output->writeln('manager reply: '.$reply->toJson()); + }) + ); + } +} \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Cli/StopManagerCommandTest.php b/tests/unit/SAREhub/Component/Worker/Cli/StopManagerCommandTest.php new file mode 100644 index 0000000..fca6b2c --- /dev/null +++ b/tests/unit/SAREhub/Component/Worker/Cli/StopManagerCommandTest.php @@ -0,0 +1,78 @@ +cli = $this->createMock(Cli::class); + $this->commandService = $this->createMock(CommandService::class); + + $this->cli->method('getCommandService')->willReturn($this->commandService); + $application = new Application(); + $application->add(StopManagerCommand::newInstance() + ->withCli($this->cli)); + + $this->commandTester = new CommandTester($application->find('stop-manager')); + } + + public function testExecuteThenCommandServiceProcess() { + $this->commandService->expects($this->once())->method('process'); + $this->commandTester->execute(['manager' => 'm']); + } + + public function testExecuteThenCommandRequestTopicIsManagerId() { + $this->assertCommandRequest(function (CommandRequest $request) { + return $request->getTopic() === 'm'; + }); + $this->commandTester->execute(['manager' => 'm']); + } + + public function testExecuteThenCommandRequestNotAsync() { + $this->assertCommandRequest(function (CommandRequest $request) { + return !$request->isAsync(); + }); + $this->commandTester->execute(['manager' => 'm']); + } + + public function testExecuteThenCommandRequestCommandWorkerStop() { + $this->assertCommandRequest(function (CommandRequest $request) { + return $request->getCommand()->getName() === WorkerCommands::STOP; + }); + $this->commandTester->execute(['manager' => 'm']); + } + + public function testExecuteWhenReplyThenCommandRequestReplyCallbackOutput() { + $reply = CommandReply::success('1', 'm'); + $this->assertCommandRequest(function (CommandRequest $request) use ($reply) { + ($request->getReplyCallback())($request, $reply); + return true; + }); + + $this->commandTester->execute(['manager' => 'm']); + $this->assertContains('manager reply: '.$reply->toJson(), $this->commandTester->getDisplay()); + + } + + private function assertCommandRequest(callable $callback) { + $this->commandService->expects($this->once())->method('process') + ->with($this->callback($callback)); + } +} From afe0099404b51903f39d19a51919d25f5f5e0967 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Mon, 24 Oct 2016 10:50:34 +0200 Subject: [PATCH 123/133] fix test --- .../Worker/Manager/WorkerManager.php | 26 ++++++++++--------- .../Worker/Manager/WorkerManagerTest.php | 8 ++++++ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/SAREhub/Component/Worker/Manager/WorkerManager.php b/src/SAREhub/Component/Worker/Manager/WorkerManager.php index 7fd85fb..40b1be4 100644 --- a/src/SAREhub/Component/Worker/Manager/WorkerManager.php +++ b/src/SAREhub/Component/Worker/Manager/WorkerManager.php @@ -116,18 +116,20 @@ protected function onStartCommand(Command $command, callable $replyCallback) { protected function onStopCommand(Command $command, callable $replyCallback) { $id = $command->getParameters()['id']; - $this->getLogger()->info('send stop command to worker', ['command' => (string)$command]); - $manager = $this; - $request = CommandRequest::newInstance() - ->withTopic($id) - ->withCommand(WorkerCommands::stop($command->getCorrelationId())) - ->withReplyCallback( - function (CommandRequest $request, CommandReply $reply) use ($manager, $replyCallback, $command) { - $this->getLogger()->info('got reply', ['request' => $request, 'reply' => json_encode($reply)]); - $manager->getProcessService()->unregisterWorker($request->getTopic()); - $replyCallback($command, $reply); - }); - $this->getCommandService()->process($request); + if (in_array($id, $this->getWorkerList())) { + $this->getLogger()->info('send stop command to worker', ['command' => (string)$command]); + $manager = $this; + $request = CommandRequest::newInstance() + ->withTopic($id) + ->withCommand(WorkerCommands::stop($command->getCorrelationId())) + ->withReplyCallback( + function (CommandRequest $request, CommandReply $reply) use ($manager, $replyCallback, $command) { + $this->getLogger()->info('got reply', ['request' => $request, 'reply' => json_encode($reply)]); + $manager->getProcessService()->unregisterWorker($request->getTopic()); + $replyCallback($command, $reply); + }); + $this->getCommandService()->process($request); + } } public function onStopAllCommand(Command $command, callable $replyCallback) { diff --git a/tests/unit/SAREhub/Component/Worker/Manager/WorkerManagerTest.php b/tests/unit/SAREhub/Component/Worker/Manager/WorkerManagerTest.php index 167acac..cbc12f9 100644 --- a/tests/unit/SAREhub/Component/Worker/Manager/WorkerManagerTest.php +++ b/tests/unit/SAREhub/Component/Worker/Manager/WorkerManagerTest.php @@ -81,6 +81,7 @@ public function testStopWorkerCommandWhenExistsThenCommandServiceProcess() { } public function testStopWorkerCommandWhenReplyThenProcessServiceUnregister() { + $this->processServiceMock->method('getWorkerList')->willReturn(['worker1']); $this->processServiceMock->expects($this->once())->method('unregisterWorker')->with('worker1'); $command = ManagerCommands::stop('1', 'worker1'); @@ -93,9 +94,16 @@ public function testStopWorkerCommandWhenReplyThenProcessServiceUnregister() { $this->manager->processCommand($command, $this->replyCallback); } + public function testStopWorkerCommandWhenNotExistsThenNotSendCommand() { + $command = ManagerCommands::stop('1', 'worker2'); + $this->commandServiceMock->expects($this->never())->method('process'); + $this->manager->processCommand($command, $this->replyCallback); + } + protected function setUp() { parent::setUp(); $this->processServiceMock = $this->createMock(WorkerProcessService::class); + $this->processServiceMock->method('getWorkerList')->willReturn(['worker1']); $this->commandServiceMock = $this->createMock(CommandService::class); $this->manager = (new WorkerManager(WorkerContext::newInstance())) ->withProcessService($this->processServiceMock) From 44c6a68c7c0da12ce2b53d1c57d2019de392c41a Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Mon, 24 Oct 2016 10:50:47 +0200 Subject: [PATCH 124/133] fix test --- .../Worker/Cli/StopWorkerCommand.php | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/SAREhub/Component/Worker/Cli/StopWorkerCommand.php diff --git a/src/SAREhub/Component/Worker/Cli/StopWorkerCommand.php b/src/SAREhub/Component/Worker/Cli/StopWorkerCommand.php new file mode 100644 index 0000000..dbb49d8 --- /dev/null +++ b/src/SAREhub/Component/Worker/Cli/StopWorkerCommand.php @@ -0,0 +1,40 @@ +setName('stop-worker') + ->setDescription('stops worker in manager') + ->addArgument('manager', InputArgument::REQUIRED, 'manager id') + ->addArgument('worker', InputArgument::REQUIRED, 'manager id'); + } + + protected function execute(InputInterface $input, OutputInterface $output) { + $managerId = $input->getArgument('manager'); + $workerId = $input->getArgument('worker'); + $this->getCli()->getCommandService()->process( + CommandRequest::newInstance() + ->withTopic($managerId) + ->syncMode() + ->withCommand(ManagerCommands::stop($this->getCli()->getSessionId(), $workerId)) + ->withReplyCallback(function (CommandRequest $request, CommandReply $reply) use ($output) { + $output->writeln('manager reply: '.$reply->toJson()); + }) + ); + } +} \ No newline at end of file From 87e750d783ef5ae0942fe1731d00ff2661de1964 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Mon, 24 Oct 2016 10:51:03 +0200 Subject: [PATCH 125/133] fixes --- cli/worker-cli | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cli/worker-cli b/cli/worker-cli index d364965..d90eedc 100644 --- a/cli/worker-cli +++ b/cli/worker-cli @@ -10,6 +10,7 @@ use SAREhub\Component\Worker\Cli\Cli; use SAREhub\Component\Worker\Cli\StartManagerCommand; use SAREhub\Component\Worker\Cli\StartWorkerCommand; use SAREhub\Component\Worker\Cli\StopManagerCommand; +use SAREhub\Component\Worker\Cli\StopWorkerCommand; use SAREhub\Component\Worker\Cli\SystemdHelper; use SAREhub\Component\Worker\Command\CommandService; use SAREhub\Component\Worker\Command\JsonCommandFormat; @@ -49,5 +50,6 @@ Cli::newInstance() )->registerCommand(StartManagerCommand::newInstance()->withSystemdHelper(new SystemdHelper())) ->registerCommand(StartWorkerCommand::newInstance()) ->registerCommand(StopManagerCommand::newInstance()) + ->registerCommand(StopWorkerCommand::newInstance()) ->run(); From 5148d1a618cf5391d5f0046aa0f341c60c6d30ec Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Mon, 24 Oct 2016 15:14:28 +0200 Subject: [PATCH 126/133] topic for commands must be manager id --- src/SAREhub/Component/Worker/Manager/WorkerManagerBootstrap.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SAREhub/Component/Worker/Manager/WorkerManagerBootstrap.php b/src/SAREhub/Component/Worker/Manager/WorkerManagerBootstrap.php index 79891f3..bd1bb87 100644 --- a/src/SAREhub/Component/Worker/Manager/WorkerManagerBootstrap.php +++ b/src/SAREhub/Component/Worker/Manager/WorkerManagerBootstrap.php @@ -87,7 +87,7 @@ private function createRunnerCommandInput() { $config = $this->getRunnerConfig()->getRequiredAsMap('commandInput'); return ZmqCommandInput::newInstance() ->withCommandSubscriber(Subscriber::inContext($this->zmqContext) - ->subscribe($config->getRequired('topic')) + ->subscribe($this->getConfig()->getRequired('id')) ->connect($config->getRequired('endpoint')) )->withCommandFormat(JsonCommandFormat::newInstance()); } From bfbed10faf9c5fcdc13939dac2394a1c6e7c2869 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Mon, 24 Oct 2016 16:06:42 +0200 Subject: [PATCH 127/133] stop-manager command info when manager config not exists refactored --- src/SAREhub/Component/Worker/Cli/Cli.php | 10 +++++ .../Worker/Cli/StartManagerCommand.php | 14 ++---- .../Worker/Cli/StopManagerCommand.php | 29 ++++++++---- .../SAREhub/Component/Worker/Cli/CliTest.php | 44 ++++++++++++++++--- .../Worker/Cli/StartManagerCommandTest.php | 26 ++++------- .../Worker/Cli/StopManagerCommandTest.php | 20 ++++++++- 6 files changed, 100 insertions(+), 43 deletions(-) diff --git a/src/SAREhub/Component/Worker/Cli/Cli.php b/src/SAREhub/Component/Worker/Cli/Cli.php index 00f068c..a57ad1a 100644 --- a/src/SAREhub/Component/Worker/Cli/Cli.php +++ b/src/SAREhub/Component/Worker/Cli/Cli.php @@ -92,6 +92,16 @@ public function registerCommand(CliCommand $command) { return $this; } + public function getManagerConfigFilePath($managerId) { + $configRootPath = $this->getConfig()->getRequiredAsMap('manager')->getRequired('configRootPath'); + return $configRootPath.'/'.$managerId.'.php'; + } + + public function isManagerConfigFileExists($managerId) { + $filePath = $this->getManagerConfigFilePath($managerId); + return file_exists($filePath); + } + private function getCommandLogger(CliCommand $command) { return ($this->loggerFactory)($command->getName()); } diff --git a/src/SAREhub/Component/Worker/Cli/StartManagerCommand.php b/src/SAREhub/Component/Worker/Cli/StartManagerCommand.php index 65e4f7d..13b8a56 100644 --- a/src/SAREhub/Component/Worker/Cli/StartManagerCommand.php +++ b/src/SAREhub/Component/Worker/Cli/StartManagerCommand.php @@ -39,8 +39,8 @@ protected function configure() { protected function execute(InputInterface $input, OutputInterface $output) { $managerId = $input->getArgument('manager'); - $configPath = $this->getConfigPath($managerId); - if ($this->isConfigExists($configPath)) { + if ($this->getCli()->isManagerConfigFileExists($managerId)) { + $configPath = $this->getCli()->getManagerConfigFilePath($managerId); $this->getLogger()->info('starting manager with config ', ['config' => $configPath]); $output->writeln('starting manager with config: '.$configPath); @@ -56,20 +56,12 @@ protected function execute(InputInterface $input, OutputInterface $output) { $output->writeln('started'); } } else { + $configPath = $this->getCli()->getManagerConfigFilePath($managerId); $output->writeln("config file isn't exists"); $this->getLogger()->warning("config file isn't exists", ['config' => $configPath]); } } - private function getConfigPath($configFile) { - $configRootPath = $this->getCliConfig()->getRequiredAsMap('manager')->getRequired('configRootPath'); - return $configRootPath.'/'.$configFile.'.php'; - } - - private function isConfigExists($configPath) { - return file_exists($configPath); - } - private function getManagerUnitInstanceName($managerId) { return 'worker-manager@'.$managerId.'.service'; } diff --git a/src/SAREhub/Component/Worker/Cli/StopManagerCommand.php b/src/SAREhub/Component/Worker/Cli/StopManagerCommand.php index 240f06b..1492f83 100644 --- a/src/SAREhub/Component/Worker/Cli/StopManagerCommand.php +++ b/src/SAREhub/Component/Worker/Cli/StopManagerCommand.php @@ -25,14 +25,25 @@ protected function configure() { protected function execute(InputInterface $input, OutputInterface $output) { $managerId = $input->getArgument('manager'); - $this->getCli()->getCommandService()->process( - CommandRequest::newInstance() - ->withTopic($managerId) - ->syncMode() - ->withCommand(WorkerCommands::stop($this->getCli()->getSessionId())) - ->withReplyCallback(function (CommandRequest $request, CommandReply $reply) use ($output) { - $output->writeln('manager reply: '.$reply->toJson()); - }) - ); + if ($this->getCli()->isManagerConfigFileExists($managerId)) { + $request = $this->createStopCommandRequest($managerId, $output); + $this->getCli()->getCommandService()->process($request); + } else { + $output->writeln("manager doesn't exists"); + } + } + + private function createStopCommandRequest($managerId, $output) { + return CommandRequest::newInstance() + ->withTopic($managerId) + ->syncMode() + ->withCommand(WorkerCommands::stop($this->getCli()->getSessionId())) + ->withReplyCallback($this->createReplyCallback($output)); + } + + private function createReplyCallback($output) { + return function (CommandRequest $request, CommandReply $reply) use ($output) { + $output->writeln('manager reply: '.$reply->toJson()); + }; } } \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Cli/CliTest.php b/tests/unit/SAREhub/Component/Worker/Cli/CliTest.php index a8be439..c719423 100644 --- a/tests/unit/SAREhub/Component/Worker/Cli/CliTest.php +++ b/tests/unit/SAREhub/Component/Worker/Cli/CliTest.php @@ -1,6 +1,8 @@ application = $this->createMock(Application::class); $this->commandService = $this->createMock(CommandService::class); - $this->bootstrap = Cli::newInstance() + $this->cli = Cli::newInstance() ->withApplication($this->application) ->withCommandService($this->commandService); } public function testRunThenCommandServiceStart() { $this->commandService->expects($this->once())->method('start'); - $this->bootstrap->run(); + $this->cli->run(); } public function testRunThenApplicationRun() { $this->application->expects($this->once())->method('run'); - $this->bootstrap->run(); + $this->cli->run(); } public function testRunThenCommandServiceStop() { $this->commandService->expects($this->once())->method('stop'); - $this->bootstrap->run(); + $this->cli->run(); } + public function testGetManagerConfigFilePath() { + $this->cli = $this->createPartialMock(Cli::class, ['getConfig']); + $vfsRoot = vfsStream::setup(); + $this->cli->method('getConfig')->willReturn(new Parameters([ + 'manager' => [ + 'configRootPath' => $vfsRoot->url() + ] + ])); + $this->assertEquals($vfsRoot->url().'/manager1.php', $this->cli->getManagerConfigFilePath('manager1')); + } + + public function testIsManagerConfigFileExistsWhenNotExistsThenReturnFalse() { + $this->cli = $this->createPartialMock(Cli::class, ['getConfig']); + $vfsRoot = vfsStream::setup(); + $this->cli->method('getConfig')->willReturn(new Parameters([ + 'manager' => [ + 'configRootPath' => $vfsRoot->url() + ] + ])); + $this->assertFalse($this->cli->isManagerConfigFileExists('manager1')); + } + public function testIsManagerConfigFileExistsWhenExistsThenReturnTrue() { + $this->cli = $this->createPartialMock(Cli::class, ['getConfig']); + $vfsRoot = vfsStream::setup(); + $vfsRoot->addChild(vfsStream::newFile('manager1.php')); + $this->cli->method('getConfig')->willReturn(new Parameters([ + 'manager' => [ + 'configRootPath' => $vfsRoot->url() + ] + ])); + $this->assertTrue($this->cli->isManagerConfigFileExists('manager1')); + } } diff --git a/tests/unit/SAREhub/Component/Worker/Cli/StartManagerCommandTest.php b/tests/unit/SAREhub/Component/Worker/Cli/StartManagerCommandTest.php index 41ddefa..1d4c72a 100644 --- a/tests/unit/SAREhub/Component/Worker/Cli/StartManagerCommandTest.php +++ b/tests/unit/SAREhub/Component/Worker/Cli/StartManagerCommandTest.php @@ -1,8 +1,6 @@ vfsRoot = vfsStream::setup('root'); $this->cli = $this->createMock(Cli::class); - $this->cli->method('getConfig')->willReturn(new Parameters([ - 'manager' => [ - 'configRootPath' => $this->vfsRoot->url() - ] - ])); + + $this->cli->method('getManagerConfigFilePath')->willReturn('path'); $this->systemdHelper = $this->createMock(SystemdHelper::class); $application = new Application(); $application->add(StartManagerCommand::newInstance() @@ -41,40 +33,40 @@ protected function setUp() { } public function testExecuteWhenConfigFileNotExistsThenPrint() { + $this->cli->method('isManagerConfigFileExists')->willReturn(false); $this->commandTester->execute(['manager' => 'file']); $output = $this->commandTester->getDisplay(); $this->assertContains("config file isn't exists", $output); } public function testExecuteWhenNoConfigThenSystemdStartNotCall() { + $this->cli->method('isManagerConfigFileExists')->willReturn(false); $this->systemdHelper->expects($this->never())->method('start'); $this->commandTester->execute(['manager' => 'file']); } public function testExecuteWhenConfigThenSystemdStart() { - $this->vfsRoot->addChild(vfsStream::newFile('manager.php')); + $this->cli->method('isManagerConfigFileExists')->willReturn(true); $this->systemdHelper->expects($this->once())->method('start')->with('worker-manager@manager.service'); $this->commandTester->execute(['manager' => 'manager']); } public function testExecuteWhenConfigThenOutputStarting() { - $this->vfsRoot->addChild(vfsStream::newFile('manager.php')); + $this->cli->method('isManagerConfigFileExists')->willReturn(true); $this->commandTester->execute(['manager' => 'manager']); - - $configPath = $this->vfsRoot->url().'/manager.php'; $output = $this->commandTester->getDisplay(); - $this->assertContains("starting manager with config: ".$configPath, $output); + $this->assertContains("starting manager with config: path", $output); } public function testExecuteWhenConfigThenOutputUnitInstanceName() { - $this->vfsRoot->addChild(vfsStream::newFile('manager.php')); + $this->cli->method('isManagerConfigFileExists')->willReturn(true); $this->commandTester->execute(['manager' => 'manager']); $output = $this->commandTester->getDisplay(); $this->assertContains("manager instance unit name: worker-manager@manager.service", $output); } public function testExecuteWhenConfigThenOutputSystemdStart() { - $this->vfsRoot->addChild(vfsStream::newFile('manager.php')); + $this->cli->method('isManagerConfigFileExists')->willReturn(true); $this->systemdHelper->method('start')->willReturn('systemd_start'); $this->commandTester->execute(['manager' => 'manager']); $output = $this->commandTester->getDisplay(); diff --git a/tests/unit/SAREhub/Component/Worker/Cli/StopManagerCommandTest.php b/tests/unit/SAREhub/Component/Worker/Cli/StopManagerCommandTest.php index fca6b2c..7c92c45 100644 --- a/tests/unit/SAREhub/Component/Worker/Cli/StopManagerCommandTest.php +++ b/tests/unit/SAREhub/Component/Worker/Cli/StopManagerCommandTest.php @@ -11,6 +11,7 @@ use Symfony\Component\Console\Tester\CommandTester; class StopManagerCommandTest extends TestCase { + private $cli; /** @@ -33,12 +34,26 @@ protected function setUp() { $this->commandTester = new CommandTester($application->find('stop-manager')); } - public function testExecuteThenCommandServiceProcess() { + public function testExecuteWhenConfigNotExistsThenNotCommandServiceProcess() { + $this->cli->method('isManagerConfigFileExists')->willReturn(false); + $this->commandService->expects($this->never())->method('process'); + $this->commandTester->execute(['manager' => 'm']); + } + + public function testExecuteWhenConfigNotExistsThenOutputInfo() { + $this->cli->method('isManagerConfigFileExists')->willReturn(false); + $this->commandTester->execute(['manager' => 'm']); + $this->assertContains("manager doesn't exists", $this->commandTester->getDisplay()); + } + + public function testExecuteWhenConfigThenCommandServiceProcess() { + $this->cli->method('isManagerConfigFileExists')->willReturn(true); $this->commandService->expects($this->once())->method('process'); $this->commandTester->execute(['manager' => 'm']); } public function testExecuteThenCommandRequestTopicIsManagerId() { + $this->cli->method('isManagerConfigFileExists')->willReturn(true); $this->assertCommandRequest(function (CommandRequest $request) { return $request->getTopic() === 'm'; }); @@ -46,6 +61,7 @@ public function testExecuteThenCommandRequestTopicIsManagerId() { } public function testExecuteThenCommandRequestNotAsync() { + $this->cli->method('isManagerConfigFileExists')->willReturn(true); $this->assertCommandRequest(function (CommandRequest $request) { return !$request->isAsync(); }); @@ -53,6 +69,7 @@ public function testExecuteThenCommandRequestNotAsync() { } public function testExecuteThenCommandRequestCommandWorkerStop() { + $this->cli->method('isManagerConfigFileExists')->willReturn(true); $this->assertCommandRequest(function (CommandRequest $request) { return $request->getCommand()->getName() === WorkerCommands::STOP; }); @@ -60,6 +77,7 @@ public function testExecuteThenCommandRequestCommandWorkerStop() { } public function testExecuteWhenReplyThenCommandRequestReplyCallbackOutput() { + $this->cli->method('isManagerConfigFileExists')->willReturn(true); $reply = CommandReply::success('1', 'm'); $this->assertCommandRequest(function (CommandRequest $request) use ($reply) { ($request->getReplyCallback())($request, $reply); From e00cda1404a8b7bbf0682b5b2163d86f3386e50d Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Mon, 24 Oct 2016 16:52:44 +0200 Subject: [PATCH 128/133] refactored --- .../Worker/Cli/StartManagerCommand.php | 8 +++---- .../Worker/Cli/StartWorkerCommand.php | 22 +++++++++++-------- .../Worker/Cli/StopManagerCommand.php | 6 ++--- .../Worker/Cli/StartManagerCommandTest.php | 2 +- .../Worker/Cli/StartWorkerCommandTest.php | 17 ++++++++++++++ .../Worker/Cli/StopManagerCommandTest.php | 2 +- 6 files changed, 39 insertions(+), 18 deletions(-) diff --git a/src/SAREhub/Component/Worker/Cli/StartManagerCommand.php b/src/SAREhub/Component/Worker/Cli/StartManagerCommand.php index 13b8a56..262d7c8 100644 --- a/src/SAREhub/Component/Worker/Cli/StartManagerCommand.php +++ b/src/SAREhub/Component/Worker/Cli/StartManagerCommand.php @@ -46,18 +46,18 @@ protected function execute(InputInterface $input, OutputInterface $output) { $unitName = $this->getManagerUnitInstanceName($managerId); $this->getLogger()->info('manager unit instance name: ', ['unit' => $unitName]); - $output->write('manager instance unit name: '.$unitName.' '); + $output->write('manager instance unit name: '.$unitName.' '); $return = $this->systemdHelper->start($unitName); if (!empty($return)) { $this->getLogger()->info('systemd start output: '.$return); - $output->writeln('systemd start output: '.$return); + $output->writeln('systemd start output: '.$return); } else { - $output->writeln('started'); + $output->writeln('started'); } } else { $configPath = $this->getCli()->getManagerConfigFilePath($managerId); - $output->writeln("config file isn't exists"); + $output->writeln("manager config file isn't exists"); $this->getLogger()->warning("config file isn't exists", ['config' => $configPath]); } } diff --git a/src/SAREhub/Component/Worker/Cli/StartWorkerCommand.php b/src/SAREhub/Component/Worker/Cli/StartWorkerCommand.php index 85ef986..19a696f 100644 --- a/src/SAREhub/Component/Worker/Cli/StartWorkerCommand.php +++ b/src/SAREhub/Component/Worker/Cli/StartWorkerCommand.php @@ -27,15 +27,19 @@ protected function execute(InputInterface $input, OutputInterface $output) { $managerId = $input->getArgument('manager'); $workerId = $input->getArgument('worker'); - $this->getCli()->getCommandService()->process( - CommandRequest::newInstance() - ->withTopic($managerId) - ->syncMode() - ->withCommand(ManagerCommands::start($this->getCli()->getSessionId(), $workerId)) - ->withReplyCallback(function (CommandRequest $request, CommandReply $reply) use ($output) { - $output->writeln('manager reply: '.$reply->toJson()); - }) - ); + if ($this->getCli()->isManagerConfigFileExists($managerId)) { + $this->getCli()->getCommandService()->process( + CommandRequest::newInstance() + ->withTopic($managerId) + ->syncMode() + ->withCommand(ManagerCommands::start($this->getCli()->getSessionId(), $workerId)) + ->withReplyCallback(function (CommandRequest $request, CommandReply $reply) use ($output) { + $output->writeln('manager reply: '.$reply->toJson()); + }) + ); + } else { + $output->writeln("manager isn't exists"); + } } } \ No newline at end of file diff --git a/src/SAREhub/Component/Worker/Cli/StopManagerCommand.php b/src/SAREhub/Component/Worker/Cli/StopManagerCommand.php index 1492f83..7f1f9eb 100644 --- a/src/SAREhub/Component/Worker/Cli/StopManagerCommand.php +++ b/src/SAREhub/Component/Worker/Cli/StopManagerCommand.php @@ -29,7 +29,7 @@ protected function execute(InputInterface $input, OutputInterface $output) { $request = $this->createStopCommandRequest($managerId, $output); $this->getCli()->getCommandService()->process($request); } else { - $output->writeln("manager doesn't exists"); + $output->writeln("manager isn't exists"); } } @@ -41,9 +41,9 @@ private function createStopCommandRequest($managerId, $output) { ->withReplyCallback($this->createReplyCallback($output)); } - private function createReplyCallback($output) { + private function createReplyCallback(OutputInterface $output) { return function (CommandRequest $request, CommandReply $reply) use ($output) { - $output->writeln('manager reply: '.$reply->toJson()); + $output->writeln('manager reply: '.$reply->toJson()); }; } } \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Cli/StartManagerCommandTest.php b/tests/unit/SAREhub/Component/Worker/Cli/StartManagerCommandTest.php index 1d4c72a..a31160c 100644 --- a/tests/unit/SAREhub/Component/Worker/Cli/StartManagerCommandTest.php +++ b/tests/unit/SAREhub/Component/Worker/Cli/StartManagerCommandTest.php @@ -36,7 +36,7 @@ public function testExecuteWhenConfigFileNotExistsThenPrint() { $this->cli->method('isManagerConfigFileExists')->willReturn(false); $this->commandTester->execute(['manager' => 'file']); $output = $this->commandTester->getDisplay(); - $this->assertContains("config file isn't exists", $output); + $this->assertContains("manager config file isn't exists", $output); } public function testExecuteWhenNoConfigThenSystemdStartNotCall() { diff --git a/tests/unit/SAREhub/Component/Worker/Cli/StartWorkerCommandTest.php b/tests/unit/SAREhub/Component/Worker/Cli/StartWorkerCommandTest.php index da779c6..6edd5ed 100644 --- a/tests/unit/SAREhub/Component/Worker/Cli/StartWorkerCommandTest.php +++ b/tests/unit/SAREhub/Component/Worker/Cli/StartWorkerCommandTest.php @@ -34,12 +34,26 @@ protected function setUp() { $this->commandTester = new CommandTester($application->find('start-worker')); } + public function testExecuteWhenManagerNotExistsThenNotProcess() { + $this->cli->method('isManagerConfigFileExists')->willReturn(false); + $this->commandService->expects($this->never())->method('process'); + $this->commandTester->execute(['manager' => 'm', 'worker' => 'w']); + } + + public function testExecuteWhenManagerNotExistsThenOutputError() { + $this->cli->method('isManagerConfigFileExists')->willReturn(false); + $this->commandTester->execute(['manager' => 'm', 'worker' => 'w']); + $this->assertContains("manager isn't exists", $this->commandTester->getDisplay()); + } + public function testExecuteThenCommandServiceProcess() { + $this->cli->method('isManagerConfigFileExists')->willReturn(true); $this->commandService->expects($this->once())->method('process'); $this->commandTester->execute(['manager' => 'm', 'worker' => 'w']); } public function testExecuteThenCommandRequestTopicIsManagerId() { + $this->cli->method('isManagerConfigFileExists')->willReturn(true); $this->assertCommandRequest(function (CommandRequest $request) { return $request->getTopic() === 'm'; }); @@ -47,6 +61,7 @@ public function testExecuteThenCommandRequestTopicIsManagerId() { } public function testExecuteThenCommandRequestNotAsync() { + $this->cli->method('isManagerConfigFileExists')->willReturn(true); $this->assertCommandRequest(function (CommandRequest $request) { return !$request->isAsync(); }); @@ -54,6 +69,7 @@ public function testExecuteThenCommandRequestNotAsync() { } public function testExecuteThenCommandRequestCommandManagerStartWorker() { + $this->cli->method('isManagerConfigFileExists')->willReturn(true); $this->assertCommandRequest(function (CommandRequest $request) { return $request->getCommand()->getName() === ManagerCommands::START; }); @@ -61,6 +77,7 @@ public function testExecuteThenCommandRequestCommandManagerStartWorker() { } public function testExecuteWhenReplyThenCommandRequestReplyCallbackOutput() { + $this->cli->method('isManagerConfigFileExists')->willReturn(true); $reply = CommandReply::success('1', 'm'); $this->assertCommandRequest(function (CommandRequest $request) use ($reply) { ($request->getReplyCallback())($request, $reply); diff --git a/tests/unit/SAREhub/Component/Worker/Cli/StopManagerCommandTest.php b/tests/unit/SAREhub/Component/Worker/Cli/StopManagerCommandTest.php index 7c92c45..0cd3d4e 100644 --- a/tests/unit/SAREhub/Component/Worker/Cli/StopManagerCommandTest.php +++ b/tests/unit/SAREhub/Component/Worker/Cli/StopManagerCommandTest.php @@ -43,7 +43,7 @@ public function testExecuteWhenConfigNotExistsThenNotCommandServiceProcess() { public function testExecuteWhenConfigNotExistsThenOutputInfo() { $this->cli->method('isManagerConfigFileExists')->willReturn(false); $this->commandTester->execute(['manager' => 'm']); - $this->assertContains("manager doesn't exists", $this->commandTester->getDisplay()); + $this->assertContains("manager isn't exists", $this->commandTester->getDisplay()); } public function testExecuteWhenConfigThenCommandServiceProcess() { From 6817871525f47c2919f37ec48881a42db66e0986 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Tue, 25 Oct 2016 10:49:16 +0200 Subject: [PATCH 129/133] added cli command forwarders systemd service --- cli/worker-cli-forwarder@.service | 11 +++++++++ cli/workerCliForwarder.php | 41 +++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 cli/worker-cli-forwarder@.service create mode 100644 cli/workerCliForwarder.php diff --git a/cli/worker-cli-forwarder@.service b/cli/worker-cli-forwarder@.service new file mode 100644 index 0000000..d14e730 --- /dev/null +++ b/cli/worker-cli-forwarder@.service @@ -0,0 +1,11 @@ +[Unit] +Description=Worker CLI command forwarder unit from sarehub/component_worker +Documentation=http://packagist.org/packages/sarehub/component_worker + +[Service] +Environment="WORKERCLI_FORWARDER=path_to_workerCliForwarder.php" +ExecStart=/usr/bin/php ${WORKERCLI_FORWARDER} %I + +TimeoutStopSec=30 +KillMode=process +KillSignal=SIGINT \ No newline at end of file diff --git a/cli/workerCliForwarder.php b/cli/workerCliForwarder.php new file mode 100644 index 0000000..cf10e53 --- /dev/null +++ b/cli/workerCliForwarder.php @@ -0,0 +1,41 @@ +getRequiredAsMap('manager'); + +$zmqContext = new ZMQContext(); +$forwarderConfig = $cliManagerConfig->getRequiredAsMap('forwarders')->getRequiredAsMap($type); + +$device = ZmqForwarderDevice::getBuilder() + ->frontend(Subscriber::inContext($zmqContext) + ->bind($forwarderConfig->getRequired('input')) + )->backend(Publisher::inContext($zmqContext) + ->bind($forwarderConfig->getRequired('output')) + )->build(); + +$canRun = true; +$onStop = function () use (&$canRun) { + $canRun = false; +}; + +PcntlSignals::getGlobal() + ->handle(PcntlSignals::SIGINT, $onStop) + ->handle(PcntlSignals::SIGTERM, $onStop) + ->install(); +$device->setTimerCallback(function () use (&$canRun) { + PcntlSignals::getGlobal()->checkPendingSignals(); + return $canRun; +}); + +$device->run(); + From 3f89d165873cde500bb0b1cb49d4155383e9de41 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Tue, 25 Oct 2016 10:53:55 +0200 Subject: [PATCH 130/133] added tests --- .../Worker/Cli/StopWorkerCommand.php | 23 +++-- .../Worker/Cli/StopWorkerCommandTest.php | 96 +++++++++++++++++++ 2 files changed, 110 insertions(+), 9 deletions(-) create mode 100644 tests/unit/SAREhub/Component/Worker/Cli/StopWorkerCommandTest.php diff --git a/src/SAREhub/Component/Worker/Cli/StopWorkerCommand.php b/src/SAREhub/Component/Worker/Cli/StopWorkerCommand.php index dbb49d8..44fe916 100644 --- a/src/SAREhub/Component/Worker/Cli/StopWorkerCommand.php +++ b/src/SAREhub/Component/Worker/Cli/StopWorkerCommand.php @@ -27,14 +27,19 @@ protected function configure() { protected function execute(InputInterface $input, OutputInterface $output) { $managerId = $input->getArgument('manager'); $workerId = $input->getArgument('worker'); - $this->getCli()->getCommandService()->process( - CommandRequest::newInstance() - ->withTopic($managerId) - ->syncMode() - ->withCommand(ManagerCommands::stop($this->getCli()->getSessionId(), $workerId)) - ->withReplyCallback(function (CommandRequest $request, CommandReply $reply) use ($output) { - $output->writeln('manager reply: '.$reply->toJson()); - }) - ); + + if ($this->getCli()->isManagerConfigFileExists($managerId)) { + $this->getCli()->getCommandService()->process( + CommandRequest::newInstance() + ->withTopic($managerId) + ->syncMode() + ->withCommand(ManagerCommands::stop($this->getCli()->getSessionId(), $workerId)) + ->withReplyCallback(function (CommandRequest $request, CommandReply $reply) use ($output) { + $output->writeln('manager reply: '.$reply->toJson()); + }) + ); + } else { + $output->writeln("manager isn't exists"); + } } } \ No newline at end of file diff --git a/tests/unit/SAREhub/Component/Worker/Cli/StopWorkerCommandTest.php b/tests/unit/SAREhub/Component/Worker/Cli/StopWorkerCommandTest.php new file mode 100644 index 0000000..ee3ed56 --- /dev/null +++ b/tests/unit/SAREhub/Component/Worker/Cli/StopWorkerCommandTest.php @@ -0,0 +1,96 @@ +cli = $this->createMock(Cli::class); + $this->commandService = $this->createMock(CommandService::class); + + $this->cli->method('getCommandService')->willReturn($this->commandService); + $application = new Application(); + $application->add(StopWorkerCommand::newInstance() + ->withCli($this->cli)); + + $this->commandTester = new CommandTester($application->find('stop-worker')); + } + + public function testExecuteWhenManagerNotExistsThenNotProcess() { + $this->cli->method('isManagerConfigFileExists')->willReturn(false); + $this->commandService->expects($this->never())->method('process'); + $this->commandTester->execute(['manager' => 'm', 'worker' => 'w']); + } + + public function testExecuteWhenManagerNotExistsThenOutputError() { + $this->cli->method('isManagerConfigFileExists')->willReturn(false); + $this->commandTester->execute(['manager' => 'm', 'worker' => 'w']); + $this->assertContains("manager isn't exists", $this->commandTester->getDisplay()); + } + + public function testExecuteThenCommandServiceProcess() { + $this->cli->method('isManagerConfigFileExists')->willReturn(true); + $this->commandService->expects($this->once())->method('process'); + $this->commandTester->execute(['manager' => 'm', 'worker' => 'w']); + } + + public function testExecuteThenCommandRequestTopicIsManagerId() { + $this->cli->method('isManagerConfigFileExists')->willReturn(true); + $this->assertCommandRequest(function (CommandRequest $request) { + return $request->getTopic() === 'm'; + }); + $this->commandTester->execute(['manager' => 'm', 'worker' => 'w']); + } + + public function testExecuteThenCommandRequestNotAsync() { + $this->cli->method('isManagerConfigFileExists')->willReturn(true); + $this->assertCommandRequest(function (CommandRequest $request) { + return !$request->isAsync(); + }); + $this->commandTester->execute(['manager' => 'm', 'worker' => 'w']); + } + + public function testExecuteThenCommandRequestCommandManagerStartWorker() { + $this->cli->method('isManagerConfigFileExists')->willReturn(true); + $this->assertCommandRequest(function (CommandRequest $request) { + return $request->getCommand()->getName() === ManagerCommands::STOP; + }); + $this->commandTester->execute(['manager' => 'm', 'worker' => 'w']); + } + + public function testExecuteWhenReplyThenCommandRequestReplyCallbackOutput() { + $this->cli->method('isManagerConfigFileExists')->willReturn(true); + $reply = CommandReply::success('1', 'm'); + $this->assertCommandRequest(function (CommandRequest $request) use ($reply) { + ($request->getReplyCallback())($request, $reply); + return true; + }); + + $this->commandTester->execute(['manager' => 'm', 'worker' => 'w']); + $this->assertContains('manager reply: '.$reply->toJson(), $this->commandTester->getDisplay()); + + } + + private function assertCommandRequest(callable $callback) { + $this->commandService->expects($this->once())->method('process') + ->with($this->callback($callback)); + } +} From 733f52b603f04c60aa77c7be651c2538eb4eafe2 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Tue, 25 Oct 2016 10:54:14 +0200 Subject: [PATCH 131/133] fixes --- cli/managers/test.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/managers/test.php b/cli/managers/test.php index 9caf096..16ce432 100644 --- a/cli/managers/test.php +++ b/cli/managers/test.php @@ -25,7 +25,7 @@ 'startCommands' => [ ManagerCommands::start('1', '1'), ManagerCommands::start('2', '2'), - ManagerCommands::start('3', '3'), + ManagerCommands::start('3', '3') ] ], 'logger' => [ From 6ad0900fe8ba5d5cec748f867053c3071bcff8b8 Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Tue, 25 Oct 2016 11:11:03 +0200 Subject: [PATCH 132/133] fix check commandline arguments test --- .../Component/Worker/Manager/WorkerProcessFactoryTest.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessFactoryTest.php b/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessFactoryTest.php index 3fa13df..faaa912 100644 --- a/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessFactoryTest.php +++ b/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessFactoryTest.php @@ -3,6 +3,7 @@ use PHPUnit\Framework\TestCase; use SAREhub\Component\Worker\Manager\WorkerProcessFactory; use Symfony\Component\Process\Process; +use Symfony\Component\Process\ProcessUtils; class WorkerProcessFactoryTest extends TestCase { @@ -21,7 +22,11 @@ public function testCreateWhenOnlyRunnerScriptPathSets() { $this->assertSame('id', $workerProcess->getId()); $process = $workerProcess->getProcess(); $this->assertInstanceOf(Process::class, $process); - $this->assertEquals('"php" "runner.php" "id"', $process->getCommandLine()); + $expectedCommandLine = ProcessUtils::escapeArgument('php'); + $expectedCommandLine .= ' '.ProcessUtils::escapeArgument('runner.php'); + $expectedCommandLine .= ' '.ProcessUtils::escapeArgument('id'); + + $this->assertEquals($expectedCommandLine, $process->getCommandLine()); } public function testCreateWithCustomWorkingDirectory() { From 87ea38396a4daf3c6f1efaa48c9f5398679b6e4f Mon Sep 17 00:00:00 2001 From: "a.wasiak@sare.pl" Date: Tue, 25 Oct 2016 11:16:19 +0200 Subject: [PATCH 133/133] fix #2 check commandline arguments test --- .../Worker/Manager/WorkerProcessFactoryTest.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessFactoryTest.php b/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessFactoryTest.php index faaa912..55353cc 100644 --- a/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessFactoryTest.php +++ b/tests/unit/SAREhub/Component/Worker/Manager/WorkerProcessFactoryTest.php @@ -22,10 +22,7 @@ public function testCreateWhenOnlyRunnerScriptPathSets() { $this->assertSame('id', $workerProcess->getId()); $process = $workerProcess->getProcess(); $this->assertInstanceOf(Process::class, $process); - $expectedCommandLine = ProcessUtils::escapeArgument('php'); - $expectedCommandLine .= ' '.ProcessUtils::escapeArgument('runner.php'); - $expectedCommandLine .= ' '.ProcessUtils::escapeArgument('id'); - + $expectedCommandLine = $this->getCommandLine(['php', 'runner.php', 'id']); $this->assertEquals($expectedCommandLine, $process->getCommandLine()); } @@ -46,6 +43,11 @@ public function testCreateWithArguments() { $workerProcess = $factory->create('id'); $process = $workerProcess->getProcess(); - $this->assertEquals('"php" "runner.php" "id" "arg1" "arg2"', $process->getCommandLine()); + $expectedCommandLine = $this->getCommandLine(['php', 'runner.php', 'id', 'arg1', 'arg2']); + $this->assertEquals($expectedCommandLine, $process->getCommandLine()); + } + + private function getCommandLine(array $arguments) { + return implode(' ', array_map(array(ProcessUtils::class, 'escapeArgument'), $arguments)); } }