From 024fefcf20009241d6b5aebad9fcac006ac246b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B3=D0=B4=D0=B5=D0=B2=D0=B8=D1=87=20=D0=93?= =?UTF-8?q?=D0=BB=D0=B5=D0=B1?= Date: Tue, 23 Oct 2018 17:18:14 +0300 Subject: [PATCH 01/20] Add schedule queue worker --- README.md | 8 +- composer.lock | 35 +++---- .../Handler/HandlerFabricInterface.php | 10 ++ src/Scheduler/Handler/HandlerInterface.php | 10 ++ .../HandlerWorker/HandlerWorkerInterface.php | 17 ++++ src/Scheduler/Lock/LockInterface.php | 26 +++++ src/Scheduler/Lock/RedisLock.php | 34 +++++++ src/Scheduler/Scheduler.php | 9 +- ...edulerQueueRedisClientFactoryInterface.php | 12 +++ .../SchedulerQueueWorker.php | 96 +++++++++++++++++++ .../SchedulerQueueWorkerInterface.php | 13 +++ 11 files changed, 250 insertions(+), 20 deletions(-) create mode 100644 src/Scheduler/Handler/HandlerFabricInterface.php create mode 100644 src/Scheduler/Handler/HandlerInterface.php create mode 100644 src/Scheduler/HandlerWorker/HandlerWorkerInterface.php create mode 100644 src/Scheduler/Lock/LockInterface.php create mode 100644 src/Scheduler/Lock/RedisLock.php create mode 100644 src/Scheduler/SchedulerQueueWorker/SchedulerQueueRedisClientFactoryInterface.php create mode 100644 src/Scheduler/SchedulerQueueWorker/SchedulerQueueWorker.php create mode 100644 src/Scheduler/SchedulerQueueWorker/SchedulerQueueWorkerInterface.php diff --git a/README.md b/README.md index 6836722..fdd10a5 100644 --- a/README.md +++ b/README.md @@ -5,15 +5,17 @@ Задача: * Шедулер (/src/Scheduler) должен предоставлять: - * интерфейс для добавления заданий в расписание; - * интерфейс для получения заданий из расписания для выполнения; + + интерфейс для добавления заданий в расписание; + + интерфейс для получения заданий из расписания для выполнения; * интерфейсы для добавления и получения заданий из очереди; * интерфейс для фабрики обработчиков заданий; * интерфейс для обработчика задания; * базовую реализацию воркера для выборки заданий из расписания и добавления их в очередь; * базовую реализацию воркера для получения задания из очереди, поиска обработчика для неё и запуска этого обработчика. -* Шедулер должен запускаться по крону раз в минуту, выбирать из расписания задания, которые нужно выполнить и добавлять их очередь на выполнения. + +* Шедулер должен запускаться по крону раз в минуту, выбирать из расписания задания, которые нужно выполнить и добавлять их очередь на выполнение. * Базовые реализации интерфейсов должны быть покрыты тестами. + * Основной код (/src/Topface) должен предоставлять: * возможность запуска крона через run.php; * возможность запуска обработчиков очереди через run.php; diff --git a/composer.lock b/composer.lock index 84c3c56..add9301 100644 --- a/composer.lock +++ b/composer.lock @@ -469,32 +469,32 @@ "packages-dev": [ { "name": "doctrine/instantiator", - "version": "1.0.5", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", + "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", "shasum": "" }, "require": { - "php": ">=5.3,<8.0-DEV" + "php": "^7.1" }, "require-dev": { "athletic/athletic": "~0.1.8", "ext-pdo": "*", "ext-phar": "*", - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "~2.0" + "phpunit/phpunit": "^6.2.3", + "squizlabs/php_codesniffer": "^3.0.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.2.x-dev" } }, "autoload": { @@ -519,29 +519,32 @@ "constructor", "instantiate" ], - "time": "2015-06-14T21:17:01+00:00" + "time": "2017-07-22T11:58:36+00:00" }, { "name": "myclabs/deep-copy", - "version": "1.7.0", + "version": "1.8.1", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e" + "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", - "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", + "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0" + "php": "^7.1" + }, + "replace": { + "myclabs/deep-copy": "self.version" }, "require-dev": { "doctrine/collections": "^1.0", "doctrine/common": "^2.6", - "phpunit/phpunit": "^4.1" + "phpunit/phpunit": "^7.1" }, "type": "library", "autoload": { @@ -564,7 +567,7 @@ "object", "object graph" ], - "time": "2017-10-19T19:58:43+00:00" + "time": "2018-06-11T23:09:50+00:00" }, { "name": "phar-io/manifest", diff --git a/src/Scheduler/Handler/HandlerFabricInterface.php b/src/Scheduler/Handler/HandlerFabricInterface.php new file mode 100644 index 0000000..1590bde --- /dev/null +++ b/src/Scheduler/Handler/HandlerFabricInterface.php @@ -0,0 +1,10 @@ +RedisClient->setnx($Key, 1)) { + $this->RedisClient->expire($Key, 10); + return true; + } + return false; + } + + /** + * Снимаем лок + * + * @param string $key + * + * @return mixed + */ + public function unlock(string $key) { + // TODO: Implement unlock() method. + } +} diff --git a/src/Scheduler/Scheduler.php b/src/Scheduler/Scheduler.php index afe852d..5b9a5cd 100644 --- a/src/Scheduler/Scheduler.php +++ b/src/Scheduler/Scheduler.php @@ -3,11 +3,14 @@ namespace Scheduler; use Predis\Client; +use Scheduler\Lock\LockInterface; use Scheduler\Task\SchedulerTask; use Scheduler\Task\SchedulerTaskInterface; +/** + * Класс расписания выполняемых задач + */ class Scheduler implements SchedulerInterface { - /** * @var Client */ @@ -18,6 +21,8 @@ public function __construct(SchedulerRedisClientFactoryInterface $RedisClientFac } /** + * Добавляем задачу в пул или устанавливаем новые данные для неё + * * @inheritdoc */ public function addOrSet(SchedulerTaskInterface $Task): string { @@ -30,6 +35,8 @@ public function addOrSet(SchedulerTaskInterface $Task): string { } /** + * Достаем таск из очереди и удаляем его оттуда + * * @inheritdoc */ public function getAndRemove(int $timestamp, int $count = self::LIMIT): array { diff --git a/src/Scheduler/SchedulerQueueWorker/SchedulerQueueRedisClientFactoryInterface.php b/src/Scheduler/SchedulerQueueWorker/SchedulerQueueRedisClientFactoryInterface.php new file mode 100644 index 0000000..0b1ce57 --- /dev/null +++ b/src/Scheduler/SchedulerQueueWorker/SchedulerQueueRedisClientFactoryInterface.php @@ -0,0 +1,12 @@ +Scheduler = $Scheduler; + $this->RedisClient = $RedisClientFactory->getRedisClient(); + } + + /** + * Достаем текущие задачи из планировщика и отправляем их на обработку + */ + public function publishCurrentTasks() { + // получаем таски, которые нам нужно обработать + $currentTime = time(); + $tasks = $this->Scheduler->getAndRemove($currentTime); + + + // публикуем таски в очередь обработчиков + $this->lock(); + + $handlerQueueKey = $this->getQueueKey(); + foreach($tasks as $taskId => $Task) { + $taskData = \msgpack_pack($Task->toArray()); + + $this->RedisClient->sadd($handlerQueueKey, $taskData); + } + + $this->unlock(); + } + + /** + * Установка блокировки + * + * @return bool + */ + private function lock(): bool { + $Key = $this->getLockKey(); + if ($this->RedisClient->setnx($Key, 1)) { + $this->RedisClient->expire($Key, 10); + return true; + } + return false; + } + + /** + * Снятие блокировки + */ + private function unlock() { + $Key = $this->getLockKey(); + $this->RedisClient->del([$Key]); + } + + /** + * Возвращает ключ для лока + * + * @return string + */ + private function getLockKey(): string { + return 'handler_queue_lock'; + } + + /** + * Возвращает ключ для очереди обработчиков + * + * @return string + */ + private function getQueueKey(): string { + return 'handler_queue'; + } +} diff --git a/src/Scheduler/SchedulerQueueWorker/SchedulerQueueWorkerInterface.php b/src/Scheduler/SchedulerQueueWorker/SchedulerQueueWorkerInterface.php new file mode 100644 index 0000000..abd7393 --- /dev/null +++ b/src/Scheduler/SchedulerQueueWorker/SchedulerQueueWorkerInterface.php @@ -0,0 +1,13 @@ + Date: Tue, 23 Oct 2018 17:32:42 +0300 Subject: [PATCH 02/20] controller --- .gitignore | 0 README.md | 0 composer.json | 0 composer.lock | 0 phpunit.xml.dist | 0 src/Scheduler/Scheduler.php | 0 src/Scheduler/SchedulerInterface.php | 0 .../SchedulerRedisClientFactoryInterface.php | 0 src/Scheduler/Task/SchedulerTask.php | 0 src/Scheduler/Task/SchedulerTaskInterface.php | 0 src/Topface/Controller/ControllerArgument.php | 25 +++++++++ .../ControllerArgumentInterface.php | 14 +++++ src/Topface/Controller/RunController.php | 51 +++++++++++++++++++ .../Controller/RunControllerInterface.php | 12 +++++ src/Topface/Route/RouteStrategy.php | 34 +++++++++++++ src/Topface/Route/RouteStrategyInterface.php | 16 ++++++ src/Topface/di-config.php | 9 ++++ src/Topface/run.php | 9 ++++ tests/Scheduler/Task/SchedulerTaskTest.php | 0 19 files changed, 170 insertions(+) mode change 100644 => 100755 .gitignore mode change 100644 => 100755 README.md mode change 100644 => 100755 composer.json mode change 100644 => 100755 composer.lock mode change 100644 => 100755 phpunit.xml.dist mode change 100644 => 100755 src/Scheduler/Scheduler.php mode change 100644 => 100755 src/Scheduler/SchedulerInterface.php mode change 100644 => 100755 src/Scheduler/SchedulerRedisClientFactoryInterface.php mode change 100644 => 100755 src/Scheduler/Task/SchedulerTask.php mode change 100644 => 100755 src/Scheduler/Task/SchedulerTaskInterface.php create mode 100644 src/Topface/Controller/ControllerArgument.php create mode 100644 src/Topface/Controller/ControllerArgumentInterface.php create mode 100644 src/Topface/Controller/RunController.php create mode 100644 src/Topface/Controller/RunControllerInterface.php create mode 100644 src/Topface/Route/RouteStrategy.php create mode 100644 src/Topface/Route/RouteStrategyInterface.php mode change 100644 => 100755 src/Topface/di-config.php mode change 100644 => 100755 src/Topface/run.php mode change 100644 => 100755 tests/Scheduler/Task/SchedulerTaskTest.php diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/composer.json b/composer.json old mode 100644 new mode 100755 diff --git a/composer.lock b/composer.lock old mode 100644 new mode 100755 diff --git a/phpunit.xml.dist b/phpunit.xml.dist old mode 100644 new mode 100755 diff --git a/src/Scheduler/Scheduler.php b/src/Scheduler/Scheduler.php old mode 100644 new mode 100755 diff --git a/src/Scheduler/SchedulerInterface.php b/src/Scheduler/SchedulerInterface.php old mode 100644 new mode 100755 diff --git a/src/Scheduler/SchedulerRedisClientFactoryInterface.php b/src/Scheduler/SchedulerRedisClientFactoryInterface.php old mode 100644 new mode 100755 diff --git a/src/Scheduler/Task/SchedulerTask.php b/src/Scheduler/Task/SchedulerTask.php old mode 100644 new mode 100755 diff --git a/src/Scheduler/Task/SchedulerTaskInterface.php b/src/Scheduler/Task/SchedulerTaskInterface.php old mode 100644 new mode 100755 diff --git a/src/Topface/Controller/ControllerArgument.php b/src/Topface/Controller/ControllerArgument.php new file mode 100644 index 0000000..60c4331 --- /dev/null +++ b/src/Topface/Controller/ControllerArgument.php @@ -0,0 +1,25 @@ +runType = $runType; + } + + /** + * @return int + */ + public function getRunType() { + return $this->runType; + } +} diff --git a/src/Topface/Controller/ControllerArgumentInterface.php b/src/Topface/Controller/ControllerArgumentInterface.php new file mode 100644 index 0000000..faffdec --- /dev/null +++ b/src/Topface/Controller/ControllerArgumentInterface.php @@ -0,0 +1,14 @@ +RouteStrategy = $RouteStrategy; + $this->Scheduler = $Scheduler; + } + + public function setArgument(ControllerArgumentInterface $Argument) { + $this->ControllerArgument = $Argument; + $this->RouteStrategy->setArgument($Argument); + } + + public function start() { + if ($this->RouteStrategy->shouldAdd()) { + // Добавлять в очередь задачу + $Task = new SchedulerTask(123, 'id', 1, ['test' => 1]); + $this->Scheduler->addOrSet($Task); + } elseif ($this->RouteStrategy->shouldGetFromSchedule()) { + // запускаем воркер на вытаскивание из очереди задач шедулера + + } elseif ($this->RouteStrategy->shouldHandleScheduleTask()) { + // запускаем воркер на обработку задачи + + } else { + echo sprintf('Huston, use -t 1 or -t 2'); + } + } +} diff --git a/src/Topface/Controller/RunControllerInterface.php b/src/Topface/Controller/RunControllerInterface.php new file mode 100644 index 0000000..45e41e2 --- /dev/null +++ b/src/Topface/Controller/RunControllerInterface.php @@ -0,0 +1,12 @@ +ControllerArgument = $Argument; + } + + public function shouldAdd(): bool { + return $this->ControllerArgument->getRunType() == self::ADD; + } + + public function shouldGetFromSchedule(): bool { + return $this->ControllerArgument->getRunType() == self::GET; + } + + public function shouldHandleScheduleTask(): bool { + return $this->ControllerArgument->getRunType() == self::HANDLE; + } +} diff --git a/src/Topface/Route/RouteStrategyInterface.php b/src/Topface/Route/RouteStrategyInterface.php new file mode 100644 index 0000000..28eec28 --- /dev/null +++ b/src/Topface/Route/RouteStrategyInterface.php @@ -0,0 +1,16 @@ + DI\get(SchedulerTask::class), + SchedulerInterface::class => DI\get(Scheduler::class), + RunControllerInterface::class => DI\get(RunController::class), + RouteStrategyInterface::class => DI\get(RouteStrategy::class), ]; diff --git a/src/Topface/run.php b/src/Topface/run.php old mode 100644 new mode 100755 index 7a3f910..4e38dd7 --- a/src/Topface/run.php +++ b/src/Topface/run.php @@ -1,6 +1,8 @@ addDefinitions(__DIR__ . '/config.php'); $Di = $ContainerBuilder->build(); // TODO Тут нужно получить от DI некий роутер/фронткотроллер и стартовать + + $ControllerArgument = new ControllerArgument($argv[2]); + $Controller = $Di->get(RunControllerInterface::class); + $Controller->setArgument($ControllerArgument); + $Controller->start(); + + echo PHP_EOL; } catch (Throwable $Exception) { echo sprintf('Huston, we have a problem: %s', $Exception->getMessage()); } diff --git a/tests/Scheduler/Task/SchedulerTaskTest.php b/tests/Scheduler/Task/SchedulerTaskTest.php old mode 100644 new mode 100755 From 120656ba10a7bb2822de00b085f8a94baf4155d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B3=D0=B4=D0=B5=D0=B2=D0=B8=D1=87=20=D0=93?= =?UTF-8?q?=D0=BB=D0=B5=D0=B1?= Date: Tue, 23 Oct 2018 18:02:01 +0300 Subject: [PATCH 03/20] Add HandlerWorker and HandlerInterface's --- .../Handler/HandlerFabricInterface.php | 10 -- .../Handler/HandlerFactoryInterface.php | 15 +++ src/Scheduler/Handler/HandlerInterface.php | 11 +- src/Scheduler/HandlerWorker/HandlerWorker.php | 116 ++++++++++++++++++ .../HandlerWorker/HandlerWorkerInterface.php | 6 +- 5 files changed, 142 insertions(+), 16 deletions(-) delete mode 100644 src/Scheduler/Handler/HandlerFabricInterface.php create mode 100644 src/Scheduler/Handler/HandlerFactoryInterface.php create mode 100644 src/Scheduler/HandlerWorker/HandlerWorker.php diff --git a/src/Scheduler/Handler/HandlerFabricInterface.php b/src/Scheduler/Handler/HandlerFabricInterface.php deleted file mode 100644 index 1590bde..0000000 --- a/src/Scheduler/Handler/HandlerFabricInterface.php +++ /dev/null @@ -1,10 +0,0 @@ -RedisClient = $RedisClientFactory->getRedisClient(); + $this->HandlerFactory = $HandlerFactory; + } + + /** + * Получаем новое задание из очереди и обрабатываем его + */ + public function run() { + $queueKey = $this->getQueueKey(); + + // достаем элемент из очереди + $this->lock(); + $taskData = $this->RedisClient->spop($queueKey); + $this->unlock(); + + // обрабатываем его, если он есть + if ($taskData) { + $array = (array) \msgpack_unpack($taskData); + $Task = new SchedulerTask(...\array_values($array)); + + $this->processTask($Task); + } + + // чистим память в обработчике, чтобы не текла + unset($taskData, $Task); + + // чуть-чуть спим для приличия + usleep(100); + $this->run(); + } + + /** + * Получаем хэндлер для задачи и выполняем её + * + * @param SchedulerTask $SchedulerTask Задача, которую необходимо выполнить + */ + public function processTask(SchedulerTask $SchedulerTask) { + $TaskHandler = $this->HandlerFactory->getHandler($SchedulerTask->getTypeId()); + $TaskHandler->runTask($SchedulerTask); + } + + /** + * Установка блокировки + * + * @return bool + */ + private function lock(): bool { + $Key = $this->getLockKey(); + if ($this->RedisClient->setnx($Key, 1)) { + $this->RedisClient->expire($Key, 10); + return true; + } + return false; + } + + /** + * Снятие блокировки + */ + private function unlock() { + $Key = $this->getLockKey(); + $this->RedisClient->del([$Key]); + } + + /** + * Возвращает ключ для лока + * + * @return string + */ + private function getLockKey(): string { + return 'handler_queue_lock'; + } + + /** + * Возвращает ключ для очереди обработчиков + * + * @return string + */ + private function getQueueKey(): string { + return 'handler_queue'; + } +} diff --git a/src/Scheduler/HandlerWorker/HandlerWorkerInterface.php b/src/Scheduler/HandlerWorker/HandlerWorkerInterface.php index 3f81b3a..30d6e65 100644 --- a/src/Scheduler/HandlerWorker/HandlerWorkerInterface.php +++ b/src/Scheduler/HandlerWorker/HandlerWorkerInterface.php @@ -2,16 +2,12 @@ namespace Scheduler\HandlerWorker; -use Scheduler\Task\SchedulerTask; - /** * Интерфейс обработчика очереди */ interface HandlerWorkerInterface { /** * Получаем новое задание из очереди и обрабатываем его - * - * @return SchedulerTask */ - public function processTask(): SchedulerTask; + public function run(); } \ No newline at end of file From e39458b1494d0b3b60a4dc2b5e73290683593f63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B3=D0=B4=D0=B5=D0=B2=D0=B8=D1=87=20=D0=93?= =?UTF-8?q?=D0=BB=D0=B5=D0=B1?= Date: Tue, 23 Oct 2018 18:12:53 +0300 Subject: [PATCH 04/20] Little fixes --- src/Scheduler/HandlerWorker/HandlerWorker.php | 16 ++++++++--- .../SchedulerQueueWorker.php | 2 +- src/Topface/Handler/HandlerFactory.php | 17 +++++++++++ .../Handler/Type/ConsoleTypeHandler.php | 28 +++++++++++++++++++ 4 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 src/Topface/Handler/HandlerFactory.php create mode 100644 src/Topface/Handler/Type/ConsoleTypeHandler.php diff --git a/src/Scheduler/HandlerWorker/HandlerWorker.php b/src/Scheduler/HandlerWorker/HandlerWorker.php index 15548c3..8fc4faa 100644 --- a/src/Scheduler/HandlerWorker/HandlerWorker.php +++ b/src/Scheduler/HandlerWorker/HandlerWorker.php @@ -50,10 +50,18 @@ public function run() { // обрабатываем его, если он есть if ($taskData) { - $array = (array) \msgpack_unpack($taskData); - $Task = new SchedulerTask(...\array_values($array)); - - $this->processTask($Task); + $taskDataUnpacked = (array) \msgpack_unpack($taskData); + $Task = new SchedulerTask(...\array_values($taskDataUnpacked)); + + $result = $this->processTask($Task); + + // если таска выполнилась не очень хорошо, вносим её обратно в очередь хэндлеров + if (!$result) { + //todo log here + $this->lock(); + $this->RedisClient->sadd($queueKey, [$taskData]); + $this->unlock(); + } } // чистим память в обработчике, чтобы не текла diff --git a/src/Scheduler/SchedulerQueueWorker/SchedulerQueueWorker.php b/src/Scheduler/SchedulerQueueWorker/SchedulerQueueWorker.php index 8ec1255..0d1f92a 100644 --- a/src/Scheduler/SchedulerQueueWorker/SchedulerQueueWorker.php +++ b/src/Scheduler/SchedulerQueueWorker/SchedulerQueueWorker.php @@ -48,7 +48,7 @@ public function publishCurrentTasks() { foreach($tasks as $taskId => $Task) { $taskData = \msgpack_pack($Task->toArray()); - $this->RedisClient->sadd($handlerQueueKey, $taskData); + $this->RedisClient->sadd($handlerQueueKey, [$taskData]); } $this->unlock(); diff --git a/src/Topface/Handler/HandlerFactory.php b/src/Topface/Handler/HandlerFactory.php new file mode 100644 index 0000000..309d439 --- /dev/null +++ b/src/Topface/Handler/HandlerFactory.php @@ -0,0 +1,17 @@ +getTaskId(), + implode(',', $SchedulerTask->getContext()) + ); + + return true; + } +} From 8ffe0ea4a2d8ee7c8930237a3a10f35b0220f62b Mon Sep 17 00:00:00 2001 From: Andrey Mostovoy Date: Tue, 23 Oct 2018 18:15:38 +0300 Subject: [PATCH 05/20] tf 2 --- README.md | 6 +-- src/Topface/Controller/AddController.php | 26 ++++++++++ .../Controller/AddControllerInterface.php | 11 ++++ src/Topface/Controller/ControllerFactory.php | 13 +++++ .../Controller/ControllerFactoryInterface.php | 10 ++++ ...rInterface.php => ControllerInterface.php} | 3 +- .../Controller/GetSchedullTaskController.php | 14 +++++ .../GetSchedullTaskControllerInterface.php | 11 ++++ .../HandleSchedullTaskController.php | 14 +++++ .../HandleSchedullTaskControllerInterface.php | 11 ++++ src/Topface/Controller/RunController.php | 51 ------------------- src/Topface/Route/RouteStrategy.php | 34 ------------- src/Topface/Route/RouteStrategyInterface.php | 16 ------ src/Topface/di-config.php | 18 ++++--- src/Topface/run.php | 6 +-- 15 files changed, 129 insertions(+), 115 deletions(-) create mode 100644 src/Topface/Controller/AddController.php create mode 100644 src/Topface/Controller/AddControllerInterface.php create mode 100644 src/Topface/Controller/ControllerFactory.php create mode 100644 src/Topface/Controller/ControllerFactoryInterface.php rename src/Topface/Controller/{RunControllerInterface.php => ControllerInterface.php} (51%) create mode 100644 src/Topface/Controller/GetSchedullTaskController.php create mode 100644 src/Topface/Controller/GetSchedullTaskControllerInterface.php create mode 100644 src/Topface/Controller/HandleSchedullTaskController.php create mode 100644 src/Topface/Controller/HandleSchedullTaskControllerInterface.php delete mode 100644 src/Topface/Controller/RunController.php delete mode 100644 src/Topface/Route/RouteStrategy.php delete mode 100644 src/Topface/Route/RouteStrategyInterface.php diff --git a/README.md b/README.md index fdd10a5..8291668 100755 --- a/README.md +++ b/README.md @@ -17,9 +17,9 @@ * Базовые реализации интерфейсов должны быть покрыты тестами. * Основной код (/src/Topface) должен предоставлять: - * возможность запуска крона через run.php; + + возможность запуска крона через run.php; * возможность запуска обработчиков очереди через run.php; - * возможность добавлять два-три типа задания в расписание; + + возможность добавлять два-три типа задания в расписание; * реализации необходимых для работы библиотеки интерфейсов; * обработчики заданий расписания. * Способ просмотра результатов работы заданий можно выбрать самим (логи, ES и т.п.). @@ -32,4 +32,4 @@ * [интерфейс](/src/Scheduler/Task/SchedulerTaskInterface.php) и [реализация](/src/Scheduler/Task/SchedulerTask.php) для сущности "Задание"; * [интерфейс](/src/Scheduler/SchedulerInterface.php) и [простой вариант реализации](/src/Scheduler/Scheduler.php) логики хранения расписания. -Для запуска кода и тестов советуется использовать докер-образ hub.core.tf/topface-ci:1.4. \ No newline at end of file +Для запуска кода и тестов советуется использовать докер-образ hub.core.tf/topface-ci:1.4. diff --git a/src/Topface/Controller/AddController.php b/src/Topface/Controller/AddController.php new file mode 100644 index 0000000..157c97b --- /dev/null +++ b/src/Topface/Controller/AddController.php @@ -0,0 +1,26 @@ +Scheduler = $Scheduler; + } + + public function start() { + $Task = new SchedulerTask(time() + 10, '1', 1, ['test' => 1]); + $this->Scheduler->addOrSet($Task); + $Task = new SchedulerTask(time() + 20, '2', 2, ['test' => 2]); + $this->Scheduler->addOrSet($Task); + } +} diff --git a/src/Topface/Controller/AddControllerInterface.php b/src/Topface/Controller/AddControllerInterface.php new file mode 100644 index 0000000..8a3a780 --- /dev/null +++ b/src/Topface/Controller/AddControllerInterface.php @@ -0,0 +1,11 @@ +RouteStrategy = $RouteStrategy; - $this->Scheduler = $Scheduler; - } - - public function setArgument(ControllerArgumentInterface $Argument) { - $this->ControllerArgument = $Argument; - $this->RouteStrategy->setArgument($Argument); - } - - public function start() { - if ($this->RouteStrategy->shouldAdd()) { - // Добавлять в очередь задачу - $Task = new SchedulerTask(123, 'id', 1, ['test' => 1]); - $this->Scheduler->addOrSet($Task); - } elseif ($this->RouteStrategy->shouldGetFromSchedule()) { - // запускаем воркер на вытаскивание из очереди задач шедулера - - } elseif ($this->RouteStrategy->shouldHandleScheduleTask()) { - // запускаем воркер на обработку задачи - - } else { - echo sprintf('Huston, use -t 1 or -t 2'); - } - } -} diff --git a/src/Topface/Route/RouteStrategy.php b/src/Topface/Route/RouteStrategy.php deleted file mode 100644 index 8def70f..0000000 --- a/src/Topface/Route/RouteStrategy.php +++ /dev/null @@ -1,34 +0,0 @@ -ControllerArgument = $Argument; - } - - public function shouldAdd(): bool { - return $this->ControllerArgument->getRunType() == self::ADD; - } - - public function shouldGetFromSchedule(): bool { - return $this->ControllerArgument->getRunType() == self::GET; - } - - public function shouldHandleScheduleTask(): bool { - return $this->ControllerArgument->getRunType() == self::HANDLE; - } -} diff --git a/src/Topface/Route/RouteStrategyInterface.php b/src/Topface/Route/RouteStrategyInterface.php deleted file mode 100644 index 28eec28..0000000 --- a/src/Topface/Route/RouteStrategyInterface.php +++ /dev/null @@ -1,16 +0,0 @@ - DI\get(SchedulerTask::class), SchedulerInterface::class => DI\get(Scheduler::class), - RunControllerInterface::class => DI\get(RunController::class), - RouteStrategyInterface::class => DI\get(RouteStrategy::class), + AddControllerInterface::class => DI\get(AddController::class), + GetSchedullTaskControllerInterface::class => DI\get(GetSchedullTaskController::class), + HandleSchedullTaskControllerInterface::class => DI\get(HandleSchedullTaskController::class), + ControllerFactoryInterface::class => DI\get(ControllerFactory::class), ]; diff --git a/src/Topface/run.php b/src/Topface/run.php index 4e38dd7..101a5da 100755 --- a/src/Topface/run.php +++ b/src/Topface/run.php @@ -2,7 +2,7 @@ use DI\ContainerBuilder; use Topface\Controller\ControllerArgument; -use Topface\Controller\RunControllerInterface; +use Topface\Controller\ControllerFactoryInterface; require_once __DIR__ . '/../../vendor/autoload.php'; @@ -13,8 +13,8 @@ // TODO Тут нужно получить от DI некий роутер/фронткотроллер и стартовать $ControllerArgument = new ControllerArgument($argv[2]); - $Controller = $Di->get(RunControllerInterface::class); - $Controller->setArgument($ControllerArgument); + $Factory = $Di->get(ControllerFactoryInterface::class); + $Controller = $Factory->getController($ControllerArgument); $Controller->start(); echo PHP_EOL; From f996a8f45b3b30e27a3e9ef8b22d3d37c1112f76 Mon Sep 17 00:00:00 2001 From: Andrey Mostovoy Date: Tue, 23 Oct 2018 18:31:00 +0300 Subject: [PATCH 06/20] redis --- src/Topface/Controller/ControllerArgument.php | 16 +++++++++++++ .../ControllerArgumentInterface.php | 4 ++++ src/Topface/Controller/ControllerFactory.php | 24 ++++++++++++++++++- src/Topface/Redis/RedisClientFactory.php | 21 ++++++++++++++++ src/Topface/di-config.php | 3 +++ src/Topface/run.php | 2 +- 6 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 src/Topface/Redis/RedisClientFactory.php diff --git a/src/Topface/Controller/ControllerArgument.php b/src/Topface/Controller/ControllerArgument.php index 60c4331..92046d0 100644 --- a/src/Topface/Controller/ControllerArgument.php +++ b/src/Topface/Controller/ControllerArgument.php @@ -7,6 +7,10 @@ * @task */ class ControllerArgument implements ControllerArgumentInterface { + const ADD = 1; + const GET = 2; + const HANDLE = 3; + /** * @var int */ @@ -22,4 +26,16 @@ public function __construct(int $runType) { public function getRunType() { return $this->runType; } + + public function isAdd(): bool { + return $this->runType == self::ADD; + } + + public function isGet(): bool { + return $this->runType == self::GET; + } + + public function isHandle(): bool { + return $this->runType == self::HANDLE; + } } diff --git a/src/Topface/Controller/ControllerArgumentInterface.php b/src/Topface/Controller/ControllerArgumentInterface.php index faffdec..f7ce5ee 100644 --- a/src/Topface/Controller/ControllerArgumentInterface.php +++ b/src/Topface/Controller/ControllerArgumentInterface.php @@ -11,4 +11,8 @@ interface ControllerArgumentInterface { * @return int */ public function getRunType(); + + public function isAdd(): bool; + public function isGet(): bool; + public function isHandle(): bool; } diff --git a/src/Topface/Controller/ControllerFactory.php b/src/Topface/Controller/ControllerFactory.php index 73a7c66..9255567 100644 --- a/src/Topface/Controller/ControllerFactory.php +++ b/src/Topface/Controller/ControllerFactory.php @@ -7,7 +7,29 @@ * @task */ class ControllerFactory implements ControllerFactoryInterface { + private $AddController; + private $GetController; + private $HandleController; + + public function __construct( + AddControllerInterface $AddController, + GetSchedullTaskControllerInterface $GetController, + HandleSchedullTaskController $HandleController + ) { + $this->AddController = $AddController; + $this->GetController = $GetController; + $this->HandleController = $HandleController; + } + public function getController(ControllerArgumentInterface $Argument): ControllerInterface { - // TODO: Implement getFactory() method. + if ($Argument->isAdd()) { + $this->AddController->start(); + } elseif ($Argument->isGet()) { + $this->GetController->start(); + } elseif ($Argument->isHandle()) { + $this->HandleController->start(); + } else { + throw new \RuntimeException('Cannot create controller'); + } } } diff --git a/src/Topface/Redis/RedisClientFactory.php b/src/Topface/Redis/RedisClientFactory.php new file mode 100644 index 0000000..e0e8f28 --- /dev/null +++ b/src/Topface/Redis/RedisClientFactory.php @@ -0,0 +1,21 @@ + DI\get(SchedulerTask::class), @@ -20,4 +22,5 @@ GetSchedullTaskControllerInterface::class => DI\get(GetSchedullTaskController::class), HandleSchedullTaskControllerInterface::class => DI\get(HandleSchedullTaskController::class), ControllerFactoryInterface::class => DI\get(ControllerFactory::class), + SchedulerRedisClientFactoryInterface::class => DI\get(RedisClientFactory::class), ]; diff --git a/src/Topface/run.php b/src/Topface/run.php index 101a5da..afb87e9 100755 --- a/src/Topface/run.php +++ b/src/Topface/run.php @@ -8,7 +8,7 @@ try { $ContainerBuilder = new ContainerBuilder(); - $ContainerBuilder->addDefinitions(__DIR__ . '/config.php'); + $ContainerBuilder->addDefinitions(__DIR__ . '/di-config.php'); $Di = $ContainerBuilder->build(); // TODO Тут нужно получить от DI некий роутер/фронткотроллер и стартовать From 05df7a65e62b5135993dac4a69a4983d8ca07889 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B3=D0=B4=D0=B5=D0=B2=D0=B8=D1=87=20=D0=93?= =?UTF-8?q?=D0=BB=D0=B5=D0=B1?= Date: Tue, 23 Oct 2018 18:35:13 +0300 Subject: [PATCH 07/20] Add SchedulerQueueStorage --- src/Scheduler/HandlerWorker/HandlerWorker.php | 75 +++------------ ...edulerQueueRedisClientFactoryInterface.php | 2 +- .../SchedulerQueueStorage.php | 96 +++++++++++++++++++ .../SchedulerQueueStorageInterface.php | 37 +++++++ .../SchedulerQueueWorker.php | 74 +++----------- 5 files changed, 161 insertions(+), 123 deletions(-) rename src/Scheduler/{SchedulerQueueWorker => SchedulerQueueStorage}/SchedulerQueueRedisClientFactoryInterface.php (79%) create mode 100644 src/Scheduler/SchedulerQueueStorage/SchedulerQueueStorage.php create mode 100644 src/Scheduler/SchedulerQueueStorage/SchedulerQueueStorageInterface.php diff --git a/src/Scheduler/HandlerWorker/HandlerWorker.php b/src/Scheduler/HandlerWorker/HandlerWorker.php index 8fc4faa..7b93bc1 100644 --- a/src/Scheduler/HandlerWorker/HandlerWorker.php +++ b/src/Scheduler/HandlerWorker/HandlerWorker.php @@ -5,6 +5,7 @@ use Predis\Client; use Scheduler\Handler\HandlerFactoryInterface; use Scheduler\SchedulerQueueRedisClientFactoryInterface; +use Scheduler\SchedulerQueueStorage\SchedulerQueueStorageInterface; use Scheduler\Task\SchedulerTask; /** @@ -12,11 +13,11 @@ */ class HandlerWorker implements HandlerWorkerInterface { /** - * Клиент соединения с очередью тасков + * Сторейдж доступа к очереди тасков на выполнение * - * @var Client + * @var SchedulerQueueStorageInterface */ - private $RedisClient; + private $SchedulerQueueStorage; /** * Фабрика обработчиков типов тасков @@ -26,14 +27,14 @@ class HandlerWorker implements HandlerWorkerInterface { private $HandlerFactory; /** - * @param SchedulerQueueRedisClientFactoryInterface $RedisClientFactory - * @param HandlerFactoryInterface $HandlerFactory + * @param SchedulerQueueStorageInterface $SchedulerQueueStorage + * @param HandlerFactoryInterface $HandlerFactory */ public function __construct( - SchedulerQueueRedisClientFactoryInterface $RedisClientFactory, + SchedulerQueueStorageInterface $SchedulerQueueStorage, HandlerFactoryInterface $HandlerFactory ) { - $this->RedisClient = $RedisClientFactory->getRedisClient(); + $this->SchedulerQueueStorage = $SchedulerQueueStorage; $this->HandlerFactory = $HandlerFactory; } @@ -41,31 +42,19 @@ public function __construct( * Получаем новое задание из очереди и обрабатываем его */ public function run() { - $queueKey = $this->getQueueKey(); - // достаем элемент из очереди - $this->lock(); - $taskData = $this->RedisClient->spop($queueKey); - $this->unlock(); - - // обрабатываем его, если он есть - if ($taskData) { - $taskDataUnpacked = (array) \msgpack_unpack($taskData); - $Task = new SchedulerTask(...\array_values($taskDataUnpacked)); + $Task = $this->SchedulerQueueStorage->pop(); + if ($Task) { $result = $this->processTask($Task); - // если таска выполнилась не очень хорошо, вносим её обратно в очередь хэндлеров if (!$result) { - //todo log here - $this->lock(); - $this->RedisClient->sadd($queueKey, [$taskData]); - $this->unlock(); + $this->SchedulerQueueStorage->add($Task); } } // чистим память в обработчике, чтобы не текла - unset($taskData, $Task); + unset($Task); // чуть-чуть спим для приличия usleep(100); @@ -81,44 +70,4 @@ public function processTask(SchedulerTask $SchedulerTask) { $TaskHandler = $this->HandlerFactory->getHandler($SchedulerTask->getTypeId()); $TaskHandler->runTask($SchedulerTask); } - - /** - * Установка блокировки - * - * @return bool - */ - private function lock(): bool { - $Key = $this->getLockKey(); - if ($this->RedisClient->setnx($Key, 1)) { - $this->RedisClient->expire($Key, 10); - return true; - } - return false; - } - - /** - * Снятие блокировки - */ - private function unlock() { - $Key = $this->getLockKey(); - $this->RedisClient->del([$Key]); - } - - /** - * Возвращает ключ для лока - * - * @return string - */ - private function getLockKey(): string { - return 'handler_queue_lock'; - } - - /** - * Возвращает ключ для очереди обработчиков - * - * @return string - */ - private function getQueueKey(): string { - return 'handler_queue'; - } } diff --git a/src/Scheduler/SchedulerQueueWorker/SchedulerQueueRedisClientFactoryInterface.php b/src/Scheduler/SchedulerQueueStorage/SchedulerQueueRedisClientFactoryInterface.php similarity index 79% rename from src/Scheduler/SchedulerQueueWorker/SchedulerQueueRedisClientFactoryInterface.php rename to src/Scheduler/SchedulerQueueStorage/SchedulerQueueRedisClientFactoryInterface.php index 0b1ce57..3614555 100644 --- a/src/Scheduler/SchedulerQueueWorker/SchedulerQueueRedisClientFactoryInterface.php +++ b/src/Scheduler/SchedulerQueueStorage/SchedulerQueueRedisClientFactoryInterface.php @@ -1,6 +1,6 @@ RedisClient = $RedisClientFactory->getRedisClient(); + } + + /** + * Добавляем элемент в очередь хэндлеров + * + * @param SchedulerTask $SchedulerTask + */ + public function add(SchedulerTask $SchedulerTask) { + $this->lock(); + + $taskData = \msgpack_pack($SchedulerTask->toArray()); + $this->RedisClient->sadd($this->getQueueKey(), [$taskData]); + + $this->unlock(); + } + + /** + * Достаем и удаляем элемент из очереди хэндлеров + * + * @return SchedulerTask|null + */ + public function pop() { + $this->lock(); + $taskData = $this->RedisClient->spop($this->getQueueKey()); + $this->unlock(); + + if (!$taskData) { + return null; + } + + $taskDataUnpacked = (array) \msgpack_unpack($taskData); + return new SchedulerTask(...\array_values($taskDataUnpacked)); + } + + /** + * Установка блокировки + * + * @return bool + */ + private function lock(): bool { + $Key = $this->getLockKey(); + if ($this->RedisClient->setnx($Key, 1)) { + $this->RedisClient->expire($Key, 10); + return true; + } + return false; + } + + /** + * Снятие блокировки + */ + private function unlock() { + $Key = $this->getLockKey(); + $this->RedisClient->del([$Key]); + } + + /** + * Возвращает ключ для лока + * + * @return string + */ + public function getLockKey(): string { + return 'handler_queue_lock'; + } + + /** + * Возвращает ключ для очереди обработчиков + * + * @return string + */ + public function getQueueKey(): string { + return 'handler_queue'; + } +} diff --git a/src/Scheduler/SchedulerQueueStorage/SchedulerQueueStorageInterface.php b/src/Scheduler/SchedulerQueueStorage/SchedulerQueueStorageInterface.php new file mode 100644 index 0000000..95e20de --- /dev/null +++ b/src/Scheduler/SchedulerQueueStorage/SchedulerQueueStorageInterface.php @@ -0,0 +1,37 @@ +Scheduler = $Scheduler; - $this->RedisClient = $RedisClientFactory->getRedisClient(); + $this->SchedulerQueueStorage = $SchedulerQueueStorage; } /** @@ -40,57 +41,12 @@ public function publishCurrentTasks() { $currentTime = time(); $tasks = $this->Scheduler->getAndRemove($currentTime); - - // публикуем таски в очередь обработчиков - $this->lock(); - - $handlerQueueKey = $this->getQueueKey(); + /** + * @var int $taskId + * @var SchedulerTask $Task + */ foreach($tasks as $taskId => $Task) { - $taskData = \msgpack_pack($Task->toArray()); - - $this->RedisClient->sadd($handlerQueueKey, [$taskData]); + $this->SchedulerQueueStorage->add($Task); } - - $this->unlock(); - } - - /** - * Установка блокировки - * - * @return bool - */ - private function lock(): bool { - $Key = $this->getLockKey(); - if ($this->RedisClient->setnx($Key, 1)) { - $this->RedisClient->expire($Key, 10); - return true; - } - return false; - } - - /** - * Снятие блокировки - */ - private function unlock() { - $Key = $this->getLockKey(); - $this->RedisClient->del([$Key]); - } - - /** - * Возвращает ключ для лока - * - * @return string - */ - private function getLockKey(): string { - return 'handler_queue_lock'; - } - - /** - * Возвращает ключ для очереди обработчиков - * - * @return string - */ - private function getQueueKey(): string { - return 'handler_queue'; } } From 345ad1482d1d0a590938b01ac36adfb1e7f38be6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B3=D0=B4=D0=B5=D0=B2=D0=B8=D1=87=20=D0=93?= =?UTF-8?q?=D0=BB=D0=B5=D0=B1?= Date: Tue, 23 Oct 2018 18:44:24 +0300 Subject: [PATCH 08/20] Add loggers --- composer.json | 3 +- composer.lock | 127 +++++++++++++++++- src/Scheduler/HandlerWorker/HandlerWorker.php | 34 ++++- src/Scheduler/Lock/LockInterface.php | 26 ---- src/Scheduler/Lock/RedisLock.php | 34 ----- .../SchedulerQueueWorker.php | 18 ++- 6 files changed, 176 insertions(+), 66 deletions(-) delete mode 100644 src/Scheduler/Lock/LockInterface.php delete mode 100644 src/Scheduler/Lock/RedisLock.php diff --git a/composer.json b/composer.json index 93ff7a4..418375e 100755 --- a/composer.json +++ b/composer.json @@ -16,7 +16,8 @@ "php": "^7.0", "ext-msgpack": "~2.0.0", "predis/predis": "v1.0.1", - "php-di/php-di": "~6.0.0" + "php-di/php-di": "~6.0.0", + "monolog/monolog": "~1.23" }, "require-dev": { "phpunit/phpunit": "~6.5" diff --git a/composer.lock b/composer.lock index add9301..8040f21 100755 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e69ee380cebb8ba02372bd02524ac12f", + "content-hash": "3b2ff97fcbbc1eaaf2453cd2307c6136", "packages": [ { "name": "jeremeamia/SuperClosure", @@ -64,6 +64,84 @@ ], "time": "2018-03-21T22:21:57+00:00" }, + { + "name": "monolog/monolog", + "version": "1.23.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/fd8c787753b3a2ad11bc60c063cff1358a32a3b4", + "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/log": "~1.0" + }, + "provide": { + "psr/log-implementation": "1.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^2.4.9 || ^3.0", + "doctrine/couchdb": "~1.0@dev", + "graylog2/gelf-php": "~1.0", + "jakub-onderka/php-parallel-lint": "0.9", + "php-amqplib/php-amqplib": "~2.4", + "php-console/php-console": "^3.1.3", + "phpunit/phpunit": "~4.5", + "phpunit/phpunit-mock-objects": "2.3.0", + "ruflin/elastica": ">=0.90 <3.0", + "sentry/sentry": "^0.13", + "swiftmailer/swiftmailer": "^5.3|^6.0" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-mongo": "Allow sending log messages to a MongoDB server", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "php-console/php-console": "Allow sending log messages to Google Chrome", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server", + "sentry/sentry": "Allow sending log messages to a Sentry server" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "http://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "time": "2017-06-19T01:22:40+00:00" + }, { "name": "nikic/php-parser", "version": "v4.1.0", @@ -357,6 +435,53 @@ ], "time": "2017-02-14T16:28:37+00:00" }, + { + "name": "psr/log", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2016-10-10T12:19:37+00:00" + }, { "name": "symfony/polyfill-php56", "version": "v1.9.0", diff --git a/src/Scheduler/HandlerWorker/HandlerWorker.php b/src/Scheduler/HandlerWorker/HandlerWorker.php index 7b93bc1..4c1d637 100644 --- a/src/Scheduler/HandlerWorker/HandlerWorker.php +++ b/src/Scheduler/HandlerWorker/HandlerWorker.php @@ -2,7 +2,9 @@ namespace Scheduler\HandlerWorker; +use Exception; use Predis\Client; +use Psr\Log\LoggerInterface; use Scheduler\Handler\HandlerFactoryInterface; use Scheduler\SchedulerQueueRedisClientFactoryInterface; use Scheduler\SchedulerQueueStorage\SchedulerQueueStorageInterface; @@ -26,16 +28,26 @@ class HandlerWorker implements HandlerWorkerInterface { */ private $HandlerFactory; + /** + * Логгер для записи событий + * + * @var LoggerInterface + */ + private $Logger; + /** * @param SchedulerQueueStorageInterface $SchedulerQueueStorage * @param HandlerFactoryInterface $HandlerFactory + * @param LoggerInterface $Logger */ public function __construct( SchedulerQueueStorageInterface $SchedulerQueueStorage, - HandlerFactoryInterface $HandlerFactory + HandlerFactoryInterface $HandlerFactory, + LoggerInterface $Logger ) { $this->SchedulerQueueStorage = $SchedulerQueueStorage; $this->HandlerFactory = $HandlerFactory; + $this->Logger = $Logger; } /** @@ -49,6 +61,12 @@ public function run() { $result = $this->processTask($Task); if (!$result) { + $this->Logger->error( + sprintf( + 'Task #%s failed and restarted', + $Task->getTaskId() + ) + ); $this->SchedulerQueueStorage->add($Task); } } @@ -68,6 +86,18 @@ public function run() { */ public function processTask(SchedulerTask $SchedulerTask) { $TaskHandler = $this->HandlerFactory->getHandler($SchedulerTask->getTypeId()); - $TaskHandler->runTask($SchedulerTask); + try { + $TaskHandler->runTask($SchedulerTask); + } catch (Exception $Ex) { + $this->Logger->error( + sprintf( + 'Task #%s handler raise an exception %s, message: %s\n%s', + $SchedulerTask->getTaskId(), + get_class($Ex), + $Ex->getMessage(), + $Ex->getTraceAsString() + ) + ); + } } } diff --git a/src/Scheduler/Lock/LockInterface.php b/src/Scheduler/Lock/LockInterface.php deleted file mode 100644 index b1cc35b..0000000 --- a/src/Scheduler/Lock/LockInterface.php +++ /dev/null @@ -1,26 +0,0 @@ -RedisClient->setnx($Key, 1)) { - $this->RedisClient->expire($Key, 10); - return true; - } - return false; - } - - /** - * Снимаем лок - * - * @param string $key - * - * @return mixed - */ - public function unlock(string $key) { - // TODO: Implement unlock() method. - } -} diff --git a/src/Scheduler/SchedulerQueueWorker/SchedulerQueueWorker.php b/src/Scheduler/SchedulerQueueWorker/SchedulerQueueWorker.php index 168447f..d994693 100644 --- a/src/Scheduler/SchedulerQueueWorker/SchedulerQueueWorker.php +++ b/src/Scheduler/SchedulerQueueWorker/SchedulerQueueWorker.php @@ -2,6 +2,8 @@ namespace Scheduler\SchedulerQueueWorker; +use Exception; +use Psr\Log\LoggerInterface; use Scheduler\SchedulerInterface; use Scheduler\SchedulerQueueStorage\SchedulerQueueStorage; use Scheduler\SchedulerQueueStorage\SchedulerQueueStorageInterface; @@ -21,16 +23,24 @@ class SchedulerQueueWorker implements SchedulerQueueWorkerInterface { */ private $SchedulerQueueStorage; + /** + * @var LoggerInterface + */ + private $Logger; + /** * @param SchedulerQueueStorageInterface $SchedulerQueueStorage * @param SchedulerInterface $Scheduler + * @param LoggerInterface $Logger */ public function __construct( SchedulerQueueStorageInterface $SchedulerQueueStorage, - SchedulerInterface $Scheduler + SchedulerInterface $Scheduler, + LoggerInterface $Logger ) { $this->Scheduler = $Scheduler; $this->SchedulerQueueStorage = $SchedulerQueueStorage; + $this->Logger = $Logger; } /** @@ -46,7 +56,11 @@ public function publishCurrentTasks() { * @var SchedulerTask $Task */ foreach($tasks as $taskId => $Task) { - $this->SchedulerQueueStorage->add($Task); + try { + $this->SchedulerQueueStorage->add($Task); + } catch (Exception $Ex) { + $this->Logger->error($Ex); + } } } } From 8071a6c0310fc59850067396e2e0d71048e9acd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B3=D0=B4=D0=B5=D0=B2=D0=B8=D1=87=20=D0=93?= =?UTF-8?q?=D0=BB=D0=B5=D0=B1?= Date: Tue, 23 Oct 2018 18:58:56 +0300 Subject: [PATCH 09/20] Change redis factory interface --- .../SchedulerQueueRedisClientFactoryInterface.php | 12 ------------ .../SchedulerQueueStorage/SchedulerQueueStorage.php | 7 ++++--- .../SchedulerRedisClientFactoryInterface.php | 10 +++++++++- 3 files changed, 13 insertions(+), 16 deletions(-) delete mode 100644 src/Scheduler/SchedulerQueueStorage/SchedulerQueueRedisClientFactoryInterface.php diff --git a/src/Scheduler/SchedulerQueueStorage/SchedulerQueueRedisClientFactoryInterface.php b/src/Scheduler/SchedulerQueueStorage/SchedulerQueueRedisClientFactoryInterface.php deleted file mode 100644 index 3614555..0000000 --- a/src/Scheduler/SchedulerQueueStorage/SchedulerQueueRedisClientFactoryInterface.php +++ /dev/null @@ -1,12 +0,0 @@ -RedisClient = $RedisClientFactory->getRedisClient(); + $this->RedisClient = $RedisClientFactory->getRedisQueueClient(); } /** diff --git a/src/Scheduler/SchedulerRedisClientFactoryInterface.php b/src/Scheduler/SchedulerRedisClientFactoryInterface.php index a8b53a9..410e4dc 100755 --- a/src/Scheduler/SchedulerRedisClientFactoryInterface.php +++ b/src/Scheduler/SchedulerRedisClientFactoryInterface.php @@ -5,9 +5,17 @@ use Predis\Client; interface SchedulerRedisClientFactoryInterface { - /** + * Получаем редис для расписания тасок + * * @return Client */ public function getRedisClient(): Client; + + /** + * Получаем редис для очередей разборщиков + * + * @return Client + */ + public function getRedisQueueClient(): Client; } From 72d6c9a7a983e988f376d63123cb0567698f83dc Mon Sep 17 00:00:00 2001 From: Andrey Mostovoy Date: Tue, 23 Oct 2018 18:59:42 +0300 Subject: [PATCH 10/20] controller 3 --- .../Controller/GetSchedullTaskController.php | 17 ++++++++++++++++- .../Controller/HandleSchedullTaskController.php | 17 ++++++++++++++++- src/Topface/di-config.php | 8 ++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/Topface/Controller/GetSchedullTaskController.php b/src/Topface/Controller/GetSchedullTaskController.php index 6f3e2cd..c4f5e33 100644 --- a/src/Topface/Controller/GetSchedullTaskController.php +++ b/src/Topface/Controller/GetSchedullTaskController.php @@ -2,13 +2,28 @@ namespace Topface\Controller; +use Scheduler\SchedulerQueueWorker\SchedulerQueueWorkerInterface; + /** * @author Andrey Mostovoy * @task */ class GetSchedullTaskController implements GetSchedullTaskControllerInterface { + /** @var SchedulerQueueWorkerInterface */ + private $SchedulerQueueWorker; + + /** + * GetSchedullTaskController constructor. + * @param SchedulerQueueWorkerInterface $SchedulerQueueWorker + */ + public function __construct(SchedulerQueueWorkerInterface $SchedulerQueueWorker) { + $this->SchedulerQueueWorker = $SchedulerQueueWorker; + } + /** + * {@inheritdoc} + */ public function start() { - // TODO: Implement start() method. + $this->SchedulerQueueWorker->publishCurrentTasks(); } } diff --git a/src/Topface/Controller/HandleSchedullTaskController.php b/src/Topface/Controller/HandleSchedullTaskController.php index 8bfdfbf..5cec100 100644 --- a/src/Topface/Controller/HandleSchedullTaskController.php +++ b/src/Topface/Controller/HandleSchedullTaskController.php @@ -2,13 +2,28 @@ namespace Topface\Controller; +use Scheduler\HandlerWorker\HandlerWorkerInterface; + /** * @author Andrey Mostovoy * @task */ class HandleSchedullTaskController implements HandleSchedullTaskControllerInterface { + /** @var HandlerWorkerInterface */ + private $HandlerWorker; + + /** + * HandleSchedullTaskController constructor. + * @param HandlerWorkerInterface $HandlerWorker + */ + public function __construct(HandlerWorkerInterface $HandlerWorker) { + $this->HandlerWorker = $HandlerWorker; + } + /** + * {@inheritdoc} + */ public function start() { - // TODO: Implement start() method. + $this->HandlerWorker->run(); } } diff --git a/src/Topface/di-config.php b/src/Topface/di-config.php index 7993cee..605f5cc 100755 --- a/src/Topface/di-config.php +++ b/src/Topface/di-config.php @@ -1,7 +1,12 @@ DI\get(Scheduler::class), AddControllerInterface::class => DI\get(AddController::class), GetSchedullTaskControllerInterface::class => DI\get(GetSchedullTaskController::class), + HandlerWorkerInterface::class => DI\get(HandlerWorker::class), HandleSchedullTaskControllerInterface::class => DI\get(HandleSchedullTaskController::class), ControllerFactoryInterface::class => DI\get(ControllerFactory::class), SchedulerRedisClientFactoryInterface::class => DI\get(RedisClientFactory::class), + SchedulerQueueRedisClientFactoryInterface::class => DI\get(RedisClientFactory::class), + SchedulerQueueWorkerInterface::class => DI\get(SchedulerQueueWorker::class), ]; From fb918eecca7543b1898e9053b5f0e02c13bc9003 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B3=D0=B4=D0=B5=D0=B2=D0=B8=D1=87=20=D0=93?= =?UTF-8?q?=D0=BB=D0=B5=D0=B1?= Date: Tue, 23 Oct 2018 19:02:32 +0300 Subject: [PATCH 11/20] Fix redis factory interface realisation --- src/Topface/Redis/RedisClientFactory.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Topface/Redis/RedisClientFactory.php b/src/Topface/Redis/RedisClientFactory.php index e0e8f28..335ed87 100644 --- a/src/Topface/Redis/RedisClientFactory.php +++ b/src/Topface/Redis/RedisClientFactory.php @@ -10,12 +10,24 @@ * @task */ class RedisClientFactory implements SchedulerRedisClientFactoryInterface { - /** + * Получаем редис для расписания задач + * * @return Client */ public function getRedisClient(): Client { $Client = new Client(); return $Client; } + + /** + * Получаем редис для очередей разборщиков + * + * @return Client + */ + public function getRedisQueueClient(): Client { + $Client = new Client(); + + return $Client; + } } From cfdc2033a19466681477f3b6dae1880250c61186 Mon Sep 17 00:00:00 2001 From: Andrey Mostovoy Date: Tue, 23 Oct 2018 19:09:23 +0300 Subject: [PATCH 12/20] monolog --- composer.lock | 35 ++++++++++++++++------------------- src/Topface/di-config.php | 7 +++++-- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/composer.lock b/composer.lock index 8040f21..7484580 100755 --- a/composer.lock +++ b/composer.lock @@ -594,32 +594,32 @@ "packages-dev": [ { "name": "doctrine/instantiator", - "version": "1.1.0", + "version": "1.0.5", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda" + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", - "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", "shasum": "" }, "require": { - "php": "^7.1" + "php": ">=5.3,<8.0-DEV" }, "require-dev": { "athletic/athletic": "~0.1.8", "ext-pdo": "*", "ext-phar": "*", - "phpunit/phpunit": "^6.2.3", - "squizlabs/php_codesniffer": "^3.0.2" + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~2.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2.x-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { @@ -644,32 +644,29 @@ "constructor", "instantiate" ], - "time": "2017-07-22T11:58:36+00:00" + "time": "2015-06-14T21:17:01+00:00" }, { "name": "myclabs/deep-copy", - "version": "1.8.1", + "version": "1.7.0", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8" + "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", - "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", + "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", "shasum": "" }, "require": { - "php": "^7.1" - }, - "replace": { - "myclabs/deep-copy": "self.version" + "php": "^5.6 || ^7.0" }, "require-dev": { "doctrine/collections": "^1.0", "doctrine/common": "^2.6", - "phpunit/phpunit": "^7.1" + "phpunit/phpunit": "^4.1" }, "type": "library", "autoload": { @@ -692,7 +689,7 @@ "object", "object graph" ], - "time": "2018-06-11T23:09:50+00:00" + "time": "2017-10-19T19:58:43+00:00" }, { "name": "phar-io/manifest", diff --git a/src/Topface/di-config.php b/src/Topface/di-config.php index 605f5cc..c89d9d8 100755 --- a/src/Topface/di-config.php +++ b/src/Topface/di-config.php @@ -1,10 +1,12 @@ DI\get(HandleSchedullTaskController::class), ControllerFactoryInterface::class => DI\get(ControllerFactory::class), SchedulerRedisClientFactoryInterface::class => DI\get(RedisClientFactory::class), - SchedulerQueueRedisClientFactoryInterface::class => DI\get(RedisClientFactory::class), SchedulerQueueWorkerInterface::class => DI\get(SchedulerQueueWorker::class), + SchedulerQueueStorageInterface::class => DI\get(SchedulerQueueStorage::class), + LoggerInterface::class => DI\get(\Monolog\Logger::class), ]; From c42df2b1bd73550694cc8eece32efecca495197a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B3=D0=B4=D0=B5=D0=B2=D0=B8=D1=87=20=D0=93?= =?UTF-8?q?=D0=BB=D0=B5=D0=B1?= Date: Tue, 23 Oct 2018 19:31:14 +0300 Subject: [PATCH 13/20] Add handler factory --- src/Scheduler/Task/SchedulerTask.php | 2 + src/Topface/Handler/HandlerFactory.php | 41 +++++++++++++++++- src/Topface/Handler/HandlerFactoryConfig.php | 21 ++++++++++ .../Handler/HandlerFactoryConfigInterface.php | 7 ++++ .../Handler/HandlerFactoryRegister.php | 10 +++++ .../HandlerFactoryRegisterInterface.php | 10 +++++ .../Handler/Type/ConsoleHandlerInterface.php | 9 ++++ .../Handler/Type/ConsoleTypeHandler.php | 3 +- .../Handler/Type/LogHandlerInterface.php | 9 ++++ src/Topface/Handler/Type/LogTypeHandler.php | 42 +++++++++++++++++++ src/Topface/di-config.php | 10 ++++- src/Topface/run.php | 6 +++ 12 files changed, 166 insertions(+), 4 deletions(-) create mode 100644 src/Topface/Handler/HandlerFactoryConfig.php create mode 100644 src/Topface/Handler/HandlerFactoryConfigInterface.php create mode 100644 src/Topface/Handler/HandlerFactoryRegister.php create mode 100644 src/Topface/Handler/HandlerFactoryRegisterInterface.php create mode 100644 src/Topface/Handler/Type/ConsoleHandlerInterface.php create mode 100644 src/Topface/Handler/Type/LogHandlerInterface.php create mode 100644 src/Topface/Handler/Type/LogTypeHandler.php diff --git a/src/Scheduler/Task/SchedulerTask.php b/src/Scheduler/Task/SchedulerTask.php index 74a2041..fbe1ca4 100755 --- a/src/Scheduler/Task/SchedulerTask.php +++ b/src/Scheduler/Task/SchedulerTask.php @@ -3,6 +3,8 @@ namespace Scheduler\Task; class SchedulerTask implements SchedulerTaskInterface { + const CONSOLE_TASK = 1; + const LOG_TASK = 2; /** * @var int diff --git a/src/Topface/Handler/HandlerFactory.php b/src/Topface/Handler/HandlerFactory.php index 309d439..79c2da4 100644 --- a/src/Topface/Handler/HandlerFactory.php +++ b/src/Topface/Handler/HandlerFactory.php @@ -2,16 +2,55 @@ namespace Topface\Handler; +use DI\Container; +use DI\DependencyException; +use DI\NotFoundException; use Scheduler\Handler\HandlerFactoryInterface; use Scheduler\Handler\HandlerInterface; class HandlerFactory implements HandlerFactoryInterface { + /** + * @var HandlerFactoryConfig + */ + private $HandlerFactoryConfig; + + /** + * @var Container + */ + private $Di; + + /** + * HandlerFactory constructor. + * + * @param HandlerFactoryConfig $HandlerFactoryConfig + * @param Container $Di + */ + public function __construct( + HandlerFactoryConfig $HandlerFactoryConfig, + Container $Di + ) { + $this->HandlerFactoryConfig = $HandlerFactoryConfig; + $this->Di = $Di; + } + /** * @param int $typeId Тип таска для обработки * * @return HandlerInterface */ public function getHandler(\int $typeId): HandlerInterface { - // TODO: Implement getHandler() method. + $HandlerType = $this->HandlerFactoryConfig->getHandlersConfig()[$typeId]; + if (!$HandlerType) { + //todo log error + } + + try { + $Handler = $this->Di->get($HandlerType); + } catch (DependencyException $e) { + } catch (NotFoundException $e) { + //todo log error + } + + return $Handler; } } diff --git a/src/Topface/Handler/HandlerFactoryConfig.php b/src/Topface/Handler/HandlerFactoryConfig.php new file mode 100644 index 0000000..4e91479 --- /dev/null +++ b/src/Topface/Handler/HandlerFactoryConfig.php @@ -0,0 +1,21 @@ + LogTypeHandler::class, + SchedulerTask::LOG_TASK => LogTypeHandler::class, + ]; + } +} diff --git a/src/Topface/Handler/HandlerFactoryConfigInterface.php b/src/Topface/Handler/HandlerFactoryConfigInterface.php new file mode 100644 index 0000000..24e5d19 --- /dev/null +++ b/src/Topface/Handler/HandlerFactoryConfigInterface.php @@ -0,0 +1,7 @@ +Logger = $Logger; + } + + /** + * Обрабатываем таску и возвращаем результат выполнения + * + * @param SchedulerTask $SchedulerTask + * + * @return bool + */ + public function runTask(SchedulerTask $SchedulerTask): bool { + $message = sprintf( + 'Task[#%s] context: %s', + $SchedulerTask->getTaskId(), + implode(',', $SchedulerTask->getContext()) + ); + + $this->Logger->notice($message); + + return true; + } +} diff --git a/src/Topface/di-config.php b/src/Topface/di-config.php index c89d9d8..564ed77 100755 --- a/src/Topface/di-config.php +++ b/src/Topface/di-config.php @@ -20,6 +20,12 @@ use Topface\Controller\GetSchedullTaskControllerInterface; use Topface\Controller\HandleSchedullTaskController; use Topface\Controller\HandleSchedullTaskControllerInterface; +use Topface\Handler\HandlerFactoryConfig; +use Topface\Handler\HandlerFactoryConfigInterface; +use Topface\Handler\Type\ConsoleHandlerInterface; +use Topface\Handler\Type\ConsoleTypeHandler; +use Topface\Handler\Type\LogHandlerInterface; +use Topface\Handler\Type\LogTypeHandler; use Topface\Redis\RedisClientFactory; return [ @@ -33,5 +39,7 @@ SchedulerRedisClientFactoryInterface::class => DI\get(RedisClientFactory::class), SchedulerQueueWorkerInterface::class => DI\get(SchedulerQueueWorker::class), SchedulerQueueStorageInterface::class => DI\get(SchedulerQueueStorage::class), - LoggerInterface::class => DI\get(\Monolog\Logger::class), + HandlerFactoryConfigInterface::class => DI\get(HandlerFactoryConfig::class), + LogHandlerInterface::class => DI\get(LogTypeHandler::class), + ConsoleHandlerInterface::class => DI\get(ConsoleTypeHandler::class) ]; diff --git a/src/Topface/run.php b/src/Topface/run.php index afb87e9..405fe53 100755 --- a/src/Topface/run.php +++ b/src/Topface/run.php @@ -1,15 +1,21 @@ addDefinitions(__DIR__ . '/di-config.php'); $Di = $ContainerBuilder->build(); + $Di->set(LoggerInterface::class, $Monolog); + // TODO Тут нужно получить от DI некий роутер/фронткотроллер и стартовать $ControllerArgument = new ControllerArgument($argv[2]); From 6805457ac847230b9150f9a6a279a6683d66d3cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B3=D0=B4=D0=B5=D0=B2=D0=B8=D1=87=20=D0=93?= =?UTF-8?q?=D0=BB=D0=B5=D0=B1?= Date: Tue, 23 Oct 2018 19:42:44 +0300 Subject: [PATCH 14/20] Return task result in handler worker --- src/Scheduler/HandlerWorker/HandlerWorker.php | 45 ++++++++++--------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/src/Scheduler/HandlerWorker/HandlerWorker.php b/src/Scheduler/HandlerWorker/HandlerWorker.php index 4c1d637..c2a4895 100644 --- a/src/Scheduler/HandlerWorker/HandlerWorker.php +++ b/src/Scheduler/HandlerWorker/HandlerWorker.php @@ -54,40 +54,43 @@ public function __construct( * Получаем новое задание из очереди и обрабатываем его */ public function run() { - // достаем элемент из очереди - $Task = $this->SchedulerQueueStorage->pop(); + while(true) { + // достаем элемент из очереди + $Task = $this->SchedulerQueueStorage->pop(); - if ($Task) { - $result = $this->processTask($Task); + if ($Task) { + $result = $this->processTask($Task); - if (!$result) { - $this->Logger->error( - sprintf( - 'Task #%s failed and restarted', - $Task->getTaskId() - ) - ); - $this->SchedulerQueueStorage->add($Task); + if (!$result) { + $this->Logger->error( + sprintf( + 'Task #%s failed and restarted', + $Task->getTaskId() + ) + ); + $this->SchedulerQueueStorage->add($Task); + } } - } - // чистим память в обработчике, чтобы не текла - unset($Task); + // чистим память в обработчике, чтобы не текла + unset($Task); - // чуть-чуть спим для приличия - usleep(100); - $this->run(); + // чуть-чуть спим для приличия + usleep(500); + } } /** * Получаем хэндлер для задачи и выполняем её * * @param SchedulerTask $SchedulerTask Задача, которую необходимо выполнить + * + * @return bool */ - public function processTask(SchedulerTask $SchedulerTask) { + public function processTask(SchedulerTask $SchedulerTask): bool { $TaskHandler = $this->HandlerFactory->getHandler($SchedulerTask->getTypeId()); try { - $TaskHandler->runTask($SchedulerTask); + return $TaskHandler->runTask($SchedulerTask); } catch (Exception $Ex) { $this->Logger->error( sprintf( @@ -99,5 +102,7 @@ public function processTask(SchedulerTask $SchedulerTask) { ) ); } + + return false; } } From 39e5b5826ab5c83049c4ced6237806c93731bea3 Mon Sep 17 00:00:00 2001 From: Andrey Mostovoy Date: Tue, 23 Oct 2018 19:44:08 +0300 Subject: [PATCH 15/20] fix controller --- README.md | 8 ++++---- src/Topface/Controller/ControllerFactory.php | 6 +++--- src/Topface/Handler/HandlerFactory.php | 2 +- src/Topface/Redis/RedisClientFactory.php | 9 ++++++--- src/Topface/di-config.php | 5 ++++- 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 8291668..5efc10a 100755 --- a/README.md +++ b/README.md @@ -18,12 +18,12 @@ * Основной код (/src/Topface) должен предоставлять: + возможность запуска крона через run.php; - * возможность запуска обработчиков очереди через run.php; + + возможность запуска обработчиков очереди через run.php; + возможность добавлять два-три типа задания в расписание; - * реализации необходимых для работы библиотеки интерфейсов; - * обработчики заданий расписания. + + реализации необходимых для работы библиотеки интерфейсов; + + обработчики заданий расписания. * Способ просмотра результатов работы заданий можно выбрать самим (логи, ES и т.п.). -* Для хранения расписания, заданий и очереди использовать Redis. ++ Для хранения расписания, заданий и очереди использовать Redis. * Опционально: * Добавить логирование действия через PSR-3 интерфейс. * Добавить сбор статистических метрик работы шедулера. diff --git a/src/Topface/Controller/ControllerFactory.php b/src/Topface/Controller/ControllerFactory.php index 9255567..5402716 100644 --- a/src/Topface/Controller/ControllerFactory.php +++ b/src/Topface/Controller/ControllerFactory.php @@ -23,11 +23,11 @@ public function __construct( public function getController(ControllerArgumentInterface $Argument): ControllerInterface { if ($Argument->isAdd()) { - $this->AddController->start(); + return $this->AddController; } elseif ($Argument->isGet()) { - $this->GetController->start(); + return $this->GetController; } elseif ($Argument->isHandle()) { - $this->HandleController->start(); + return $this->HandleController; } else { throw new \RuntimeException('Cannot create controller'); } diff --git a/src/Topface/Handler/HandlerFactory.php b/src/Topface/Handler/HandlerFactory.php index 79c2da4..e750825 100644 --- a/src/Topface/Handler/HandlerFactory.php +++ b/src/Topface/Handler/HandlerFactory.php @@ -38,7 +38,7 @@ public function __construct( * * @return HandlerInterface */ - public function getHandler(\int $typeId): HandlerInterface { + public function getHandler(int $typeId): HandlerInterface { $HandlerType = $this->HandlerFactoryConfig->getHandlersConfig()[$typeId]; if (!$HandlerType) { //todo log error diff --git a/src/Topface/Redis/RedisClientFactory.php b/src/Topface/Redis/RedisClientFactory.php index 335ed87..f595c91 100644 --- a/src/Topface/Redis/RedisClientFactory.php +++ b/src/Topface/Redis/RedisClientFactory.php @@ -16,7 +16,9 @@ class RedisClientFactory implements SchedulerRedisClientFactoryInterface { * @return Client */ public function getRedisClient(): Client { - $Client = new Client(); + $Client = new Client([ + 'host' => 'ag-redis', + ]); return $Client; } @@ -26,8 +28,9 @@ public function getRedisClient(): Client { * @return Client */ public function getRedisQueueClient(): Client { - $Client = new Client(); - + $Client = new Client([ + 'host' => 'ag-redis', + ]); return $Client; } } diff --git a/src/Topface/di-config.php b/src/Topface/di-config.php index 564ed77..ab137a9 100755 --- a/src/Topface/di-config.php +++ b/src/Topface/di-config.php @@ -1,6 +1,7 @@ DI\get(SchedulerQueueStorage::class), HandlerFactoryConfigInterface::class => DI\get(HandlerFactoryConfig::class), LogHandlerInterface::class => DI\get(LogTypeHandler::class), - ConsoleHandlerInterface::class => DI\get(ConsoleTypeHandler::class) + ConsoleHandlerInterface::class => DI\get(ConsoleTypeHandler::class), + HandlerFactoryInterface::class => DI\get(HandlerFactory::class), ]; From ce6dbefc662adb0abd231acbf881a1e719ea7b03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B3=D0=B4=D0=B5=D0=B2=D0=B8=D1=87=20=D0=93?= =?UTF-8?q?=D0=BB=D0=B5=D0=B1?= Date: Tue, 23 Oct 2018 19:44:08 +0300 Subject: [PATCH 16/20] Make handler worker more beautiful --- src/Scheduler/HandlerWorker/HandlerWorker.php | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/Scheduler/HandlerWorker/HandlerWorker.php b/src/Scheduler/HandlerWorker/HandlerWorker.php index c2a4895..b4979e6 100644 --- a/src/Scheduler/HandlerWorker/HandlerWorker.php +++ b/src/Scheduler/HandlerWorker/HandlerWorker.php @@ -58,18 +58,20 @@ public function run() { // достаем элемент из очереди $Task = $this->SchedulerQueueStorage->pop(); - if ($Task) { - $result = $this->processTask($Task); + if (!$Task) { + continue; + } + + $result = $this->processTask($Task); - if (!$result) { - $this->Logger->error( - sprintf( - 'Task #%s failed and restarted', - $Task->getTaskId() - ) - ); - $this->SchedulerQueueStorage->add($Task); - } + if (!$result) { + $this->Logger->error( + sprintf( + 'Task #%s failed and restarted', + $Task->getTaskId() + ) + ); + $this->SchedulerQueueStorage->add($Task); } // чистим память в обработчике, чтобы не текла From ad28a91d2d43b051ef7c170f44cd95f4620b09a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B3=D0=B4=D0=B5=D0=B2=D0=B8=D1=87=20=D0=93?= =?UTF-8?q?=D0=BB=D0=B5=D0=B1?= Date: Tue, 23 Oct 2018 19:53:27 +0300 Subject: [PATCH 17/20] Fix namespaces --- src/Scheduler/HandlerWorker/HandlerWorker.php | 2 -- src/Scheduler/Scheduler.php | 1 - 2 files changed, 3 deletions(-) diff --git a/src/Scheduler/HandlerWorker/HandlerWorker.php b/src/Scheduler/HandlerWorker/HandlerWorker.php index b4979e6..173dd0b 100644 --- a/src/Scheduler/HandlerWorker/HandlerWorker.php +++ b/src/Scheduler/HandlerWorker/HandlerWorker.php @@ -3,10 +3,8 @@ namespace Scheduler\HandlerWorker; use Exception; -use Predis\Client; use Psr\Log\LoggerInterface; use Scheduler\Handler\HandlerFactoryInterface; -use Scheduler\SchedulerQueueRedisClientFactoryInterface; use Scheduler\SchedulerQueueStorage\SchedulerQueueStorageInterface; use Scheduler\Task\SchedulerTask; diff --git a/src/Scheduler/Scheduler.php b/src/Scheduler/Scheduler.php index 5b9a5cd..14300c1 100755 --- a/src/Scheduler/Scheduler.php +++ b/src/Scheduler/Scheduler.php @@ -3,7 +3,6 @@ namespace Scheduler; use Predis\Client; -use Scheduler\Lock\LockInterface; use Scheduler\Task\SchedulerTask; use Scheduler\Task\SchedulerTaskInterface; From 23a27f54ef4385cf7d4d0f2de89554450e352824 Mon Sep 17 00:00:00 2001 From: Andrey Mostovoy Date: Tue, 23 Oct 2018 19:56:00 +0300 Subject: [PATCH 18/20] fixes --- README.md | 2 +- src/Topface/Handler/HandlerFactoryConfig.php | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5efc10a..770dfec 100755 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ * Способ просмотра результатов работы заданий можно выбрать самим (логи, ES и т.п.). + Для хранения расписания, заданий и очереди использовать Redis. * Опционально: - * Добавить логирование действия через PSR-3 интерфейс. + + Добавить логирование действия через PSR-3 интерфейс. * Добавить сбор статистических метрик работы шедулера. Для упрощения работы добавлены: diff --git a/src/Topface/Handler/HandlerFactoryConfig.php b/src/Topface/Handler/HandlerFactoryConfig.php index 4e91479..7d6c1ee 100644 --- a/src/Topface/Handler/HandlerFactoryConfig.php +++ b/src/Topface/Handler/HandlerFactoryConfig.php @@ -3,6 +3,7 @@ namespace Topface\Handler; use Scheduler\Task\SchedulerTask; +use Topface\Handler\Type\ConsoleTypeHandler; use Topface\Handler\Type\LogTypeHandler; /** @@ -14,7 +15,7 @@ class HandlerFactoryConfig implements HandlerFactoryConfigInterface { */ public function getHandlersConfig(): array { return [ - SchedulerTask::CONSOLE_TASK => LogTypeHandler::class, + SchedulerTask::CONSOLE_TASK => ConsoleTypeHandler::class, SchedulerTask::LOG_TASK => LogTypeHandler::class, ]; } From b5d7f3791e9697d4f80f12c90b81314faa31bdfd Mon Sep 17 00:00:00 2001 From: Andrey Mostovoy Date: Tue, 23 Oct 2018 20:05:29 +0300 Subject: [PATCH 19/20] remove lock --- .../SchedulerQueueStorage.php | 37 ------------------- .../SchedulerQueueStorageInterface.php | 7 ---- 2 files changed, 44 deletions(-) diff --git a/src/Scheduler/SchedulerQueueStorage/SchedulerQueueStorage.php b/src/Scheduler/SchedulerQueueStorage/SchedulerQueueStorage.php index bcefb00..0205b91 100644 --- a/src/Scheduler/SchedulerQueueStorage/SchedulerQueueStorage.php +++ b/src/Scheduler/SchedulerQueueStorage/SchedulerQueueStorage.php @@ -29,12 +29,8 @@ public function __construct( * @param SchedulerTask $SchedulerTask */ public function add(SchedulerTask $SchedulerTask) { - $this->lock(); - $taskData = \msgpack_pack($SchedulerTask->toArray()); $this->RedisClient->sadd($this->getQueueKey(), [$taskData]); - - $this->unlock(); } /** @@ -43,9 +39,7 @@ public function add(SchedulerTask $SchedulerTask) { * @return SchedulerTask|null */ public function pop() { - $this->lock(); $taskData = $this->RedisClient->spop($this->getQueueKey()); - $this->unlock(); if (!$taskData) { return null; @@ -55,37 +49,6 @@ public function pop() { return new SchedulerTask(...\array_values($taskDataUnpacked)); } - /** - * Установка блокировки - * - * @return bool - */ - private function lock(): bool { - $Key = $this->getLockKey(); - if ($this->RedisClient->setnx($Key, 1)) { - $this->RedisClient->expire($Key, 10); - return true; - } - return false; - } - - /** - * Снятие блокировки - */ - private function unlock() { - $Key = $this->getLockKey(); - $this->RedisClient->del([$Key]); - } - - /** - * Возвращает ключ для лока - * - * @return string - */ - public function getLockKey(): string { - return 'handler_queue_lock'; - } - /** * Возвращает ключ для очереди обработчиков * diff --git a/src/Scheduler/SchedulerQueueStorage/SchedulerQueueStorageInterface.php b/src/Scheduler/SchedulerQueueStorage/SchedulerQueueStorageInterface.php index 95e20de..7729f25 100644 --- a/src/Scheduler/SchedulerQueueStorage/SchedulerQueueStorageInterface.php +++ b/src/Scheduler/SchedulerQueueStorage/SchedulerQueueStorageInterface.php @@ -27,11 +27,4 @@ public function pop(); * @return string */ public function getQueueKey(): string; - - /** - * Определяет ключ лока для доступа к очереди - * - * @return string - */ - public function getLockKey(): string; } From b02f99eb8cb07fd6008f65140b42df974493b950 Mon Sep 17 00:00:00 2001 From: Andrey Mostovoy Date: Tue, 23 Oct 2018 20:16:29 +0300 Subject: [PATCH 20/20] remove useless interface --- src/Topface/Handler/Type/ConsoleHandlerInterface.php | 9 --------- src/Topface/Handler/Type/ConsoleTypeHandler.php | 3 ++- src/Topface/Handler/Type/LogHandlerInterface.php | 9 --------- src/Topface/Handler/Type/LogTypeHandler.php | 3 ++- src/Topface/di-config.php | 7 ------- 5 files changed, 4 insertions(+), 27 deletions(-) delete mode 100644 src/Topface/Handler/Type/ConsoleHandlerInterface.php delete mode 100644 src/Topface/Handler/Type/LogHandlerInterface.php diff --git a/src/Topface/Handler/Type/ConsoleHandlerInterface.php b/src/Topface/Handler/Type/ConsoleHandlerInterface.php deleted file mode 100644 index cdce741..0000000 --- a/src/Topface/Handler/Type/ConsoleHandlerInterface.php +++ /dev/null @@ -1,9 +0,0 @@ - DI\get(SchedulerQueueWorker::class), SchedulerQueueStorageInterface::class => DI\get(SchedulerQueueStorage::class), HandlerFactoryConfigInterface::class => DI\get(HandlerFactoryConfig::class), - LogHandlerInterface::class => DI\get(LogTypeHandler::class), - ConsoleHandlerInterface::class => DI\get(ConsoleTypeHandler::class), HandlerFactoryInterface::class => DI\get(HandlerFactory::class), ];