diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d66a53..519f441 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,43 @@ -# CHANGELOG +# Change Log -* 0.2.1 (2016-03-30) - * HOTFIX #18 Fixed command issues (sorting and shortcut) +## [0.2.1](https://github.com/php-task/TaskBundle/tree/0.2.1) (2016-03-30) +[Full Changelog](https://github.com/php-task/TaskBundle/compare/0.2.0...0.2.1) -* 0.2.0 (2016-02-27) - * ENHANCEMENT #-- Added debug tasks command and extended storage - * ENHANCEMENT #-- Moved command name to service definition - * FEATURE #13 Added options to command schedule task for cron tasks +**Closed issues:** -* 0.1.0 (2016-01-31) +- Debug tasks should be sorted DESC for execution date [\#17](https://github.com/php-task/TaskBundle/issues/17) +- Schedule task command option e \(end-date\) bug [\#16](https://github.com/php-task/TaskBundle/issues/16) + +**Merged pull requests:** + +- Fixed command issues [\#18](https://github.com/php-task/TaskBundle/pull/18) ([wachterjohannes](https://github.com/wachterjohannes)) + +## [0.2.0](https://github.com/php-task/TaskBundle/tree/0.2.0) (2016-02-27) +[Full Changelog](https://github.com/php-task/TaskBundle/compare/0.1.0...0.2.0) + +**Fixed bugs:** + +- If handle return object output failed [\#7](https://github.com/php-task/TaskBundle/issues/7) +- Commands should only output something on error or in verbosity mode [\#6](https://github.com/php-task/TaskBundle/issues/6) + +**Closed issues:** + +- Move command names to service definition [\#4](https://github.com/php-task/TaskBundle/issues/4) + +**Merged pull requests:** + +- Added command and extended storage [\#14](https://github.com/php-task/TaskBundle/pull/14) ([wachterjohannes](https://github.com/wachterjohannes)) +- Added options to command schedule task for cron tasks [\#13](https://github.com/php-task/TaskBundle/pull/13) ([wachterjohannes](https://github.com/wachterjohannes)) + +## [0.1.0](https://github.com/php-task/TaskBundle/tree/0.1.0) (2016-01-31) +**Fixed bugs:** + +- Next Execution date should be in the future [\#12](https://github.com/php-task/TaskBundle/issues/12) + +**Merged pull requests:** + +- Add tagged service task compilerpass [\#2](https://github.com/php-task/TaskBundle/pull/2) ([wachterjohannes](https://github.com/wachterjohannes)) + + + +\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* \ No newline at end of file diff --git a/composer.json b/composer.json index d661235..932f04c 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,7 @@ ], "require": { "php": "~5.5 || ~7.0", - "php-task/php-task": "0.2.*", + "php-task/php-task": "dev-master", "symfony/http-kernel": "^2.6", "symfony/dependency-injection": "^2.6", "symfony/config": "^2.6", diff --git a/src/Command/DebugTasksCommand.php b/src/Command/DebugTasksCommand.php index b047005..f3f22f6 100644 --- a/src/Command/DebugTasksCommand.php +++ b/src/Command/DebugTasksCommand.php @@ -1,5 +1,14 @@ */ class DebugTasksCommand extends Command { /** - * @var StorageInterface + * @var TaskExecutionRepositoryInterface */ private $storage; - public function __construct($name, StorageInterface $storage) + /** + * @param string $name + * @param TaskExecutionRepositoryInterface $storage + */ + public function __construct($name, TaskExecutionRepositoryInterface $storage) { parent::__construct($name); @@ -34,8 +45,7 @@ public function __construct($name, StorageInterface $storage) protected function configure() { $this->setDescription('Debug tasks') - ->addOption('limit', 'l', InputOption::VALUE_REQUIRED, '', null) - ->addOption('key', 'k', InputOption::VALUE_REQUIRED, '', null); + ->addOption('limit', 'l', InputOption::VALUE_REQUIRED, '', null); } /** @@ -43,35 +53,22 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output) { - $key = $input->getOption('key'); $limit = $input->getOption('limit'); - if (null !== $key) { - $tasks = $this->storage->findByKey($key, $limit, 'DESC'); - } else { - $tasks = $this->storage->findAll($limit, 'DESC'); - } + $executions = $this->storage->findAll($limit); $table = new Table($output); - $table->setHeaders(['uuid', 'key', 'task-name', 'execution-date', 'completed', 'start', 'duration']); - - foreach ($tasks as $task) { - $start = null; - $duration = null; - if ($task->getLastExecution()) { - $start = $task->getLastExecution()->getFinishedAtAsDateTime()->format(\DateTime::RFC3339); - $duration = $task->getLastExecution()->getExecutionDuration(); - } + $table->setHeaders(['uuid', 'status', 'handler', 'schedule time', 'end time', 'duration']); + foreach ($executions as $execution) { $table->addRow( [ - $task->getUuid(), - $task->getKey(), - $task->getTaskName(), - $task->getExecutionDate()->format(\DateTime::RFC3339), - $task->isCompleted(), - $start, - $duration, + $execution->getUuid(), + $execution->getStatus(), + $execution->getHandlerClass(), + $execution->getScheduleTime()->format(\DateTime::RFC3339), + !$execution->getEndTime() ? '' : $execution->getEndTime()->format(\DateTime::RFC3339), + (round($execution->getDuration(), 6) * 1000000) . 'ms', ] ); } diff --git a/src/Command/RunCommand.php b/src/Command/RunCommand.php index 1684e81..f7a3c68 100644 --- a/src/Command/RunCommand.php +++ b/src/Command/RunCommand.php @@ -1,28 +1,47 @@ */ class RunCommand extends Command { + /** + * @var TaskRunnerInterface + */ + private $runner; + /** * @var SchedulerInterface */ private $scheduler; - public function __construct($name, SchedulerInterface $scheduler) + /** + * @param string $name + * @param TaskRunnerInterface $runner + * @param SchedulerInterface $scheduler + */ + public function __construct($name, TaskRunnerInterface $runner, SchedulerInterface $scheduler) { parent::__construct($name); + $this->runner = $runner; $this->scheduler = $scheduler; } @@ -39,6 +58,7 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output) { - $this->scheduler->run(); + $this->runner->runTasks(); + $this->scheduler->scheduleTasks(); } } diff --git a/src/Command/RunHandlerCommand.php b/src/Command/RunHandlerCommand.php index 388b41d..20768d5 100644 --- a/src/Command/RunHandlerCommand.php +++ b/src/Command/RunHandlerCommand.php @@ -1,30 +1,41 @@ */ class RunHandlerCommand extends Command { /** - * @var RegistryInterface + * @var TaskHandlerFactoryInterface */ - private $registry; + private $handlerFactory; - public function __construct($name, RegistryInterface $registry) + /** + * @param string $name + * @param TaskHandlerFactoryInterface $handlerFactory + */ + public function __construct($name, TaskHandlerFactoryInterface $handlerFactory) { parent::__construct($name); - $this->registry = $registry; + $this->handlerFactory = $handlerFactory; } /** @@ -33,7 +44,7 @@ public function __construct($name, RegistryInterface $registry) protected function configure() { $this->setDescription('Run pending tasks') - ->addArgument('handler', InputArgument::REQUIRED) + ->addArgument('handlerClass', InputArgument::REQUIRED) ->addArgument('workload', InputArgument::OPTIONAL); } @@ -42,14 +53,14 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output) { - $handler = $input->getArgument('handler'); + $handlerClass = $input->getArgument('handlerClass'); $workload = $input->getArgument('workload'); if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { - $output->writeln(sprintf('Run command "%s" with workload "%s"', $handler, $workload)); + $output->writeln(sprintf('Run command "%s" with workload "%s"', $handlerClass, $workload)); } - $result = $this->registry->run($handler, $workload); + $result = $this->handlerFactory->create($handlerClass)->handle($workload); if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { $output->writeln(sprintf('Result: %s', json_encode($result))); diff --git a/src/Command/ScheduleTaskCommand.php b/src/Command/ScheduleTaskCommand.php index c33bd5c..6a104b7 100644 --- a/src/Command/ScheduleTaskCommand.php +++ b/src/Command/ScheduleTaskCommand.php @@ -1,5 +1,14 @@ */ class ScheduleTaskCommand extends Command { @@ -21,11 +28,15 @@ class ScheduleTaskCommand extends Command */ private $scheduler; - public function __construct($name, SchedulerInterface $scheduler) + /** + * @param string $name + * @param SchedulerInterface $runner + */ + public function __construct($name, SchedulerInterface $runner) { parent::__construct($name); - $this->scheduler = $scheduler; + $this->scheduler = $runner; } /** @@ -38,8 +49,7 @@ protected function configure() ->addArgument('handler', InputArgument::REQUIRED) ->addArgument('workload', InputArgument::OPTIONAL) ->addOption('cron-expression', 'c', InputOption::VALUE_REQUIRED) - ->addOption('end-date', null, InputOption::VALUE_REQUIRED) - ->addOption('key', 'k', InputOption::VALUE_REQUIRED); + ->addOption('end-date', null, InputOption::VALUE_REQUIRED); } /** @@ -51,7 +61,6 @@ protected function execute(InputInterface $input, OutputInterface $output) $workload = $input->getArgument('workload'); $cronExpression = $input->getOption('cron-expression'); $endDateString = $input->getOption('end-date'); - $key = $input->getOption('key'); if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { $output->writeln(sprintf('Schedule task "%s" with workload "%s"', $handler, $workload)); @@ -68,10 +77,6 @@ protected function execute(InputInterface $input, OutputInterface $output) $taskBuilder->cron($cronExpression, new \DateTime(), $endDate); } - if ($key !== null) { - $taskBuilder->setKey($key); - } - - $taskBuilder->schedule(); + $this->scheduler->addTask($taskBuilder->getTask()); } } diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index bb29dd9..0a499f3 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -1,5 +1,14 @@ root('task') ->children() - ->enumNode('storage')->values(['array', 'doctrine'])->defaultValue('array')->end() + ->enumNode('storage')->values(['array', 'doctrine'])->defaultValue('doctrine')->end() ->arrayNode('run') ->addDefaultsIfNotSet() ->children() diff --git a/src/DependencyInjection/HandlerCompilerPass.php b/src/DependencyInjection/HandlerCompilerPass.php index 59979c1..1a953e1 100644 --- a/src/DependencyInjection/HandlerCompilerPass.php +++ b/src/DependencyInjection/HandlerCompilerPass.php @@ -1,5 +1,14 @@ */ class HandlerCompilerPass implements CompilerPassInterface { - const REGISTRY_ID = 'task.handler_registry'; + const REGISTRY_ID = 'task.handler.factory'; const HANDLER_TAG = 'task.handler'; - const ADD_FUNCTION_NAME = 'add'; - const HANDLER_NAME_ATTRIBUTE = 'handler-name'; /** * {@inheritdoc} @@ -27,16 +32,14 @@ public function process(ContainerBuilder $container) return; } - $definition = $container->findDefinition(self::REGISTRY_ID); - + $handler = []; $taggedServices = $container->findTaggedServiceIds(self::HANDLER_TAG); foreach ($taggedServices as $id => $tags) { - foreach ($tags as $attributes) { - $definition->addMethodCall( - self::ADD_FUNCTION_NAME, - [$attributes[self::HANDLER_NAME_ATTRIBUTE], new Reference($id)] - ); - } + $service = $container->getDefinition($id); + $handler[$service->getClass()] = new Reference($id); } + + $definition = $container->findDefinition(self::REGISTRY_ID); + $definition->replaceArgument(0, $handler); } } diff --git a/src/DependencyInjection/TaskCompilerPass.php b/src/DependencyInjection/TaskCompilerPass.php deleted file mode 100644 index 159fd59..0000000 --- a/src/DependencyInjection/TaskCompilerPass.php +++ /dev/null @@ -1,63 +0,0 @@ - - */ -class TaskCompilerPass implements CompilerPassInterface -{ - const SCHEDULER_ID = 'task.scheduler'; - const INTERVAL_TAG = 'task.interval'; - const KEY_ATTRIBUTE = 'key'; - const INTERVAL_ATTRIBUTE = 'interval'; - const WORKLOAD_ATTRIBUTE = 'workload'; - const CREATE_FUNCTION_NAME = 'createTaskAndSchedule'; - - /** - * {@inheritdoc} - */ - public function process(ContainerBuilder $container) - { - if (!$container->has(self::SCHEDULER_ID)) { - return; - } - - $schedulerDefinition = $container->getDefinition(self::SCHEDULER_ID); - - $taggedServices = $container->findTaggedServiceIds(self::INTERVAL_TAG); - foreach ($taggedServices as $id => $tags) { - $handlerDefinition = $container->getDefinition($id); - $tag = $handlerDefinition->getTag(HandlerCompilerPass::HANDLER_TAG); - - // TODO handle also multiple handler tag here - $handler = $tag[0][HandlerCompilerPass::HANDLER_NAME_ATTRIBUTE]; - - // remove all tasks with $id and not completed - foreach ($tags as $attributes) { - $interval = $attributes[self::INTERVAL_ATTRIBUTE]; - $workload = isset($attributes[self::WORKLOAD_ATTRIBUTE]) ? $attributes[self::WORKLOAD_ATTRIBUTE] : null; - $key = isset($attributes[self::KEY_ATTRIBUTE]) ? $attributes[self::KEY_ATTRIBUTE] : null; - - if (!$key) { - $key = $handler . '_' . $interval . '_' . serialize($workload); - } - - $schedulerDefinition->addMethodCall( - self::CREATE_FUNCTION_NAME, - [ - $handler, - $workload, - $interval, - $key, - ] - ); - } - } - } -} diff --git a/src/DependencyInjection/TaskExtension.php b/src/DependencyInjection/TaskExtension.php index 07d6734..98171b7 100644 --- a/src/DependencyInjection/TaskExtension.php +++ b/src/DependencyInjection/TaskExtension.php @@ -1,5 +1,14 @@ */ class TaskExtension extends Extension { diff --git a/src/DoctrineStorage/TaskExecutionRepository.php b/src/DoctrineStorage/TaskExecutionRepository.php new file mode 100644 index 0000000..2ad759b --- /dev/null +++ b/src/DoctrineStorage/TaskExecutionRepository.php @@ -0,0 +1,94 @@ +objectManager = $objectManager; + $this->taskExecutionRepository = $taskExecutionRepository; + } + + /** + * {@inheritdoc} + */ + public function store(TaskExecutionInterface $execution) + { + $this->objectManager->persist($execution); + + // FIXME move this flush to somewhere else (: + $this->objectManager->flush(); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function save(TaskExecutionInterface $execution) + { + $this->objectManager->persist($execution); + + // FIXME move this flush to somewhere else (: + $this->objectManager->flush(); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function findByStartTime(TaskInterface $task, \DateTime $scheduleTime) + { + return $this->taskExecutionRepository->findByScheduledTime($task, $scheduleTime); + } + + /** + * {@inheritdoc} + */ + public function findAll($limit = null) + { + return $this->taskExecutionRepository->findBy([], ['scheduleTime' => 'ASC'], $limit); + } + + /** + * {@inheritdoc} + */ + public function findScheduled() + { + return $this->taskExecutionRepository->findScheduled(new \DateTime()); + } +} diff --git a/src/DoctrineStorage/TaskRepository.php b/src/DoctrineStorage/TaskRepository.php new file mode 100644 index 0000000..7e55b9c --- /dev/null +++ b/src/DoctrineStorage/TaskRepository.php @@ -0,0 +1,83 @@ +objectManager = $objectManager; + $this->taskRepository = $taskRepository; + } + + /** + * {@inheritdoc} + */ + public function store(TaskInterface $task) + { + $this->objectManager->persist($task); + + // FIXME move this flush to somewhere else (: + $this->objectManager->flush(); + } + + /** + * {@inheritdoc} + */ + public function findAll($limit = null) + { + return $this->taskRepository->findBy([], null, $limit); + } + + /** + * {@inheritdoc} + */ + public function findEndBeforeNow() + { + return $this->taskRepository->findEndBefore(new \DateTime()); + } + + /** + * {@inheritdoc} + */ + public function clear() + { + foreach ($this->taskRepository->findAll() as $task) { + $this->objectManager->remove($task); + } + + // FIXME move this flush to somewhere else (: + $this->objectManager->flush(); + } +} diff --git a/src/Entity/Task.php b/src/Entity/Task.php index bbaad4b..875a18f 100644 --- a/src/Entity/Task.php +++ b/src/Entity/Task.php @@ -1,10 +1,23 @@ uuid; + return $this->intervalExpression; } - /** - * @param string $uuid - */ - public function setUuid($uuid) + public function getInterval() { - $this->uuid = $uuid; - } + if (null === $this->interval && null !== $this->intervalExpression) { + $this->interval = CronExpression::factory($this->intervalExpression); + } - /** - * @return TaskInterface - */ - public function getTask() - { - return $this->task; + return parent::getInterval(); } /** - * @param TaskInterface $task + * {@inheritdoc} */ - public function setTask($task) + public function setInterval(CronExpression $interval, \DateTime $firstExecution = null, \DateTime $lastExecution = null) { - $this->task = $task; - } + parent::setInterval($interval, $firstExecution, $lastExecution); - /** - * @return \DateTime - */ - public function getExecutionDate() - { - return $this->executionDate; - } - - /** - * @param \DateTime $executionDate - */ - public function setExecutionDate($executionDate) - { - $this->executionDate = $executionDate; - } - - /** - * @return bool - */ - public function isCompleted() - { - return $this->completed; - } - - /** - * @param bool $completed - */ - public function setCompleted($completed) - { - $this->completed = $completed; - } - - /** - * @return string - */ - public function getKey() - { - return $this->key; - } - - /** - * @param string $key - * - * @return $this - */ - public function setKey($key) - { - $this->key = $key; + $this->intervalExpression = $interval->getExpression(); } } diff --git a/src/Entity/TaskExecution.php b/src/Entity/TaskExecution.php new file mode 100644 index 0000000..6c00748 --- /dev/null +++ b/src/Entity/TaskExecution.php @@ -0,0 +1,33 @@ +id; + } +} diff --git a/src/Entity/TaskExecutionRepository.php b/src/Entity/TaskExecutionRepository.php new file mode 100644 index 0000000..8e39c74 --- /dev/null +++ b/src/Entity/TaskExecutionRepository.php @@ -0,0 +1,70 @@ +createQueryBuilder('e') + ->innerJoin('e.task', 't') + ->where('t.uuid = :uuid') + ->andWhere('e.scheduleTime = :scheduleTime') + ->setParameter('uuid', $task->getUuid()) + ->setParameter('scheduleTime', $scheduleTime) + ->getQuery() + ->getSingleResult(); + } catch (NoResultException $e) { + return; + } + } + + /** + * Returns scheduled task-execution. + * + * @param \DateTime|null $dateTime + * + * @return TaskExecutionInterface[] + */ + public function findScheduled(\DateTime $dateTime = null) + { + if ($dateTime === null) { + $dateTime = new \DateTime(); + } + + return $this->createQueryBuilder('e') + ->innerJoin('e.task', 't') + ->where('e.status = :status AND e.scheduleTime < :dateTime') + ->setParameter('status', TaskStatus::PLANNED) + ->setParameter('dateTime', $dateTime) + ->getQuery() + ->getResult(); + } +} diff --git a/src/Entity/TaskRepository.php b/src/Entity/TaskRepository.php index 3902662..7f670d1 100644 --- a/src/Entity/TaskRepository.php +++ b/src/Entity/TaskRepository.php @@ -1,44 +1,37 @@ createQueryBuilder('task') - ->where('task.completed = :completed') - ->andWhere('task.executionDate <= :date') - ->setParameter('completed', false) - ->setParameter('date', new \DateTime()) - ->getQuery(); - - return $query->getResult(); - } - /** - * @param string $uuid + * Returns task where last-execution is before given date-time. + * + * @param \DateTime $dateTime * - * @return Task + * @return TaskInterface[] */ - public function findByUuid($uuid) + public function findEndBefore(\DateTime $dateTime) { - $query = $this->createQueryBuilder('task') - ->where('task.uuid = :uuid') - ->setParameter('uuid', $uuid) - ->getQuery(); - - return $query->getSingleResult(); - } - - public function deleteAll() - { - $query = $this->_em->createQueryBuilder() - ->delete($this->_entityName, 'task') - ->getQuery(); - - $query->execute(); + return $this->createQueryBuilder('t') + ->where('t.lastExecution IS NULL OR t.lastExecution >= :dateTime') + ->setParameter('dateTime', $dateTime) + ->getQuery() + ->getResult(); } } diff --git a/src/EventListener/RunListener.php b/src/EventListener/RunListener.php index 1b86f53..cc0e2cb 100644 --- a/src/EventListener/RunListener.php +++ b/src/EventListener/RunListener.php @@ -1,25 +1,35 @@ */ class RunListener { /** - * @var SchedulerInterface + * @var TaskRunnerInterface */ - private $scheduler; + private $taskRunner; - public function __construct(SchedulerInterface $scheduler) + /** + * @param TaskRunnerInterface $taskRunner + */ + public function __construct(TaskRunnerInterface $taskRunner) { - $this->scheduler = $scheduler; + $this->taskRunner = $taskRunner; } /** @@ -29,6 +39,6 @@ public function __construct(SchedulerInterface $scheduler) */ public function run(Event $event) { - $this->scheduler->run(); + $this->taskRunner->runTasks(); } } diff --git a/src/Factory.php b/src/Factory.php new file mode 100644 index 0000000..e4af578 --- /dev/null +++ b/src/Factory.php @@ -0,0 +1,38 @@ +getHandlerClass(), $scheduleTime, $task->getWorkload()); + } +} diff --git a/src/Handler/TaskHandlerFactory.php b/src/Handler/TaskHandlerFactory.php new file mode 100644 index 0000000..9cd1040 --- /dev/null +++ b/src/Handler/TaskHandlerFactory.php @@ -0,0 +1,47 @@ +handler = $handler; + } + + /** + * {@inheritdoc} + */ + public function create($className) + { + if (!array_key_exists($className, $this->handler)) { + throw new TaskHandlerNotExistsException($className); + } + + return $this->handler[$className]; + } +} diff --git a/src/Resources/config/command.xml b/src/Resources/config/command.xml index fbac5ab..dd863c4 100644 --- a/src/Resources/config/command.xml +++ b/src/Resources/config/command.xml @@ -5,6 +5,7 @@ task:run + @@ -12,13 +13,13 @@ task:run:handler - + - task:schedule:task + task:schedule @@ -26,7 +27,7 @@ debug:tasks - + diff --git a/src/Resources/config/doctrine/Task.orm.xml b/src/Resources/config/doctrine/Task.orm.xml index 0297bad..24fdca5 100644 --- a/src/Resources/config/doctrine/Task.orm.xml +++ b/src/Resources/config/doctrine/Task.orm.xml @@ -2,19 +2,23 @@ - + + + + + - - - - - + + + + + + diff --git a/src/Resources/config/doctrine/TaskExecution.orm.xml b/src/Resources/config/doctrine/TaskExecution.orm.xml new file mode 100644 index 0000000..b351a37 --- /dev/null +++ b/src/Resources/config/doctrine/TaskExecution.orm.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Resources/config/listener.xml b/src/Resources/config/listener.xml index fb8b09c..c84794c 100644 --- a/src/Resources/config/listener.xml +++ b/src/Resources/config/listener.xml @@ -4,7 +4,7 @@ xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - + diff --git a/src/Resources/config/scheduler.xml b/src/Resources/config/scheduler.xml index ddcd64e..34540a1 100644 --- a/src/Resources/config/scheduler.xml +++ b/src/Resources/config/scheduler.xml @@ -3,15 +3,23 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - - + - - - - + + + + + + + + + + + + + + - diff --git a/src/Resources/config/storage/array.xml b/src/Resources/config/storage/array.xml index a520fa1..82fa292 100644 --- a/src/Resources/config/storage/array.xml +++ b/src/Resources/config/storage/array.xml @@ -3,6 +3,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - + + diff --git a/src/Resources/config/storage/doctrine.xml b/src/Resources/config/storage/doctrine.xml index 5e80117..bf46469 100644 --- a/src/Resources/config/storage/doctrine.xml +++ b/src/Resources/config/storage/doctrine.xml @@ -3,17 +3,25 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - + + + TaskBundle:Task - + + + + + + + + TaskBundle:TaskExecution + + + - + diff --git a/src/Resources/config/task_event_listener.xml b/src/Resources/config/task_event_listener.xml index 4d21911..23a08f9 100644 --- a/src/Resources/config/task_event_listener.xml +++ b/src/Resources/config/task_event_listener.xml @@ -5,8 +5,9 @@ Task\Event\Events::TASK_CREATE + Task\Event\Events::TASK_EXECUTION_CREATE Task\Event\Events::TASK_BEFORE - Task\Event\Events::TASK_AFTER + Task\Event\Events::TASK_FINISHED Task\Event\Events::TASK_PASSED Task\Event\Events::TASK_FAILED diff --git a/src/Storage/DoctrineStorage.php b/src/Storage/DoctrineStorage.php deleted file mode 100644 index 9b55713..0000000 --- a/src/Storage/DoctrineStorage.php +++ /dev/null @@ -1,125 +0,0 @@ -entityManager = $entityManager; - $this->taskRepository = $taskRepository; - } - - /** - * {@inheritdoc} - */ - public function store(TaskInterface $task) - { - $entity = new TaskEntity(); - - if ($task->getKey()) { - $oldEntity = $this->taskRepository->findOneBy( - [ - 'key' => $task->getKey(), - 'completed' => false, - ] - ); - - if ($oldEntity) { - // TODO update task (warning execution date should not be changed) - - return; - } - } - - $this->setTask($entity, $task); - - $this->entityManager->persist($entity); - $this->entityManager->flush(); - } - - /** - * {@inheritdoc} - */ - public function findScheduled() - { - return array_map( - function (TaskEntity $entity) { - return $entity->getTask(); - }, - $this->taskRepository->findScheduled() - ); - } - - /** - * {@inheritdoc} - */ - public function findAll($limit = null, $sortOrder = 'ASC') - { - return array_map( - function (TaskEntity $entity) { - return $entity->getTask(); - }, - $this->taskRepository->findBy([], ['executionDate' => $sortOrder], $limit) - ); - } - - /** - * {@inheritdoc} - */ - public function findByKey($key, $limit = null, $sortOrder = 'ASC') - { - return array_map( - function (TaskEntity $entity) { - return $entity->getTask(); - }, - $this->taskRepository->findBy(['key' => $key], ['executionDate' => $sortOrder], $limit) - ); - } - - /** - * {@inheritdoc} - */ - public function persist(TaskInterface $task) - { - $entity = $this->taskRepository->findByUuid($task->getUuid()); - $this->setTask($entity, $task); - - $this->entityManager->persist($entity); - $this->entityManager->flush(); - } - - /** - * {@inheritdoc} - */ - public function clear() - { - $this->taskRepository->deleteAll(); - $this->entityManager->flush(); - } - - private function setTask(TaskEntity $entity, TaskInterface $task) - { - $entity->setTask(clone $task); - $entity->setUuid($task->getUuid()); - $entity->setKey($task->getKey()); - $entity->setCompleted($task->isCompleted()); - $entity->setExecutionDate($task->getExecutionDate()); - } -} diff --git a/src/TaskBundle.php b/src/TaskBundle.php index 3d2383f..a32c821 100644 --- a/src/TaskBundle.php +++ b/src/TaskBundle.php @@ -5,7 +5,6 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; use Task\TaskBundle\DependencyInjection\HandlerCompilerPass; -use Task\TaskBundle\DependencyInjection\TaskCompilerPass; /** * Integrates php-task into symfony. @@ -19,6 +18,5 @@ public function build(ContainerBuilder $container) parent::build($container); $container->addCompilerPass(new HandlerCompilerPass()); - $container->addCompilerPass(new TaskCompilerPass()); } } diff --git a/tests/Functional/BootstrapTest.php b/tests/Functional/BootstrapTest.php index 26e1ae0..1dab5c7 100644 --- a/tests/Functional/BootstrapTest.php +++ b/tests/Functional/BootstrapTest.php @@ -1,11 +1,22 @@ bootKernel(); $scheduler = self::$kernel->getContainer()->get('task.scheduler'); - $storage = self::$kernel->getContainer()->get('task.storage'); + $taskRepository = self::$kernel->getContainer()->get('task.storage.task'); + $taskExecutionRepository = self::$kernel->getContainer()->get('task.storage.task_execution'); $this->assertInstanceOf(SchedulerInterface::class, $scheduler); switch (self::$kernel->getContainer()->getParameter('kernel.storage')) { case 'array': - $this->assertInstanceOf(ArrayStorage::class, $storage); + $this->assertInstanceOf(ArrayTaskRepository::class, $taskRepository); + $this->assertInstanceOf(ArrayTaskExecutionRepository::class, $taskExecutionRepository); break; case 'doctrine': - $this->assertInstanceOf(DoctrineStorage::class, $storage); + $this->assertInstanceOf(TaskRepository::class, $taskRepository); + $this->assertInstanceOf(TaskExecutionRepository::class, $taskExecutionRepository); break; default: $this->fail('storage not supported'); diff --git a/tests/Functional/HandlerRegistryTest.php b/tests/Functional/HandlerRegistryTest.php deleted file mode 100644 index ab11186..0000000 --- a/tests/Functional/HandlerRegistryTest.php +++ /dev/null @@ -1,33 +0,0 @@ -bootKernel(); - $this->registry = self::$kernel->getContainer()->get('task.handler_registry'); - } - - public function testHas() - { - $this->assertTrue($this->registry->has('test')); - $this->assertFalse($this->registry->has('test-1')); - } - - public function testRun() - { - $this->assertEquals('daolkrow', $this->registry->run('test', 'workload')); - } -} diff --git a/tests/Functional/SchedulerTest.php b/tests/Functional/SchedulerTest.php deleted file mode 100644 index e75d7c3..0000000 --- a/tests/Functional/SchedulerTest.php +++ /dev/null @@ -1,63 +0,0 @@ -bootKernel(); - $this->scheduler = self::$kernel->getContainer()->get('task.scheduler'); - $this->storage = self::$kernel->getContainer()->get('task.storage'); - } - - public function testSchedule() - { - $this->storage->clear(); - - $this->scheduler->schedule(new Task('test', 'workload')); - - $scheduled = $this->storage->findScheduled(); - $this->assertCount(1, $scheduled); - $this->assertEquals('test', $scheduled[0]->getTaskName()); - $this->assertEquals('workload', $scheduled[0]->getWorkload()); - $this->assertFalse($scheduled[0]->isCompleted()); - } - - public function testRun() - { - $this->storage->clear(); - - $this->scheduler->schedule(new Task('test', 'workload')); - $this->scheduler->run(); - - $scheduled = $this->storage->findScheduled(); - $this->assertCount(0, $scheduled); - - $all = $this->storage->findAll(); - $this->assertCount(1, $all); - $this->assertEquals('test', $all[0]->getTaskName()); - $this->assertEquals('workload', $all[0]->getWorkload()); - $this->assertTrue($all[0]->isCompleted()); - $this->assertEquals('daolkrow', $all[0]->getResult()); - } - - // TODO daily -} diff --git a/tests/Functional/TaskHandlerFactoryTest.php b/tests/Functional/TaskHandlerFactoryTest.php new file mode 100644 index 0000000..b545575 --- /dev/null +++ b/tests/Functional/TaskHandlerFactoryTest.php @@ -0,0 +1,36 @@ +bootKernel(); + $this->taskHandlerFactory = self::$kernel->getContainer()->get('task.handler.factory'); + } + + public function testRun() + { + $this->assertInstanceOf(\TestHandler::class, $this->taskHandlerFactory->create(\TestHandler::class)); + } +} diff --git a/tests/Unit/Command/RunCommandTest.php b/tests/Unit/Command/RunCommandTest.php deleted file mode 100644 index 129b0ac..0000000 --- a/tests/Unit/Command/RunCommandTest.php +++ /dev/null @@ -1,32 +0,0 @@ -prophesize(SchedulerInterface::class); - $command = new RunCommand('task:run', $scheduler->reveal()); - - $this->assertEquals('task:run', $command->getName()); - } - - public function testRun() - { - $input = $this->prophesize(InputInterface::class); - $output = $this->prophesize(OutputInterface::class); - - $scheduler = $this->prophesize(SchedulerInterface::class); - $command = new RunCommand('task:run', $scheduler->reveal()); - - $command->run($input->reveal(), $output->reveal()); - - $scheduler->run()->shouldBeCalledTimes(1); - } -} diff --git a/tests/Unit/Command/RunHandlerCommandTest.php b/tests/Unit/Command/RunHandlerCommandTest.php deleted file mode 100644 index 86456f5..0000000 --- a/tests/Unit/Command/RunHandlerCommandTest.php +++ /dev/null @@ -1,52 +0,0 @@ -prophesize(RegistryInterface::class); - $command = new RunHandlerCommand('task:run:handler', $scheduler->reveal()); - - $this->assertEquals('task:run:handler', $command->getName()); - } - - public function runProvider() - { - return [ - ['test-handler', 'test-workload'], - ['test-handler-1', 'test-workload-1'], - ]; - } - - /** - * @dataProvider runProvider - */ - public function testRun($handlerName, $workload) - { - $input = $this->prophesize(InputInterface::class); - $output = $this->prophesize(OutputInterface::class); - - $input->bind(Argument::any())->willReturn(true); - $input->validate()->willReturn(true); - $input->isInteractive()->willReturn(false); - $input->hasArgument('command')->willReturn(false); - - $input->getArgument('handler')->willReturn($handlerName); - $input->getArgument('workload')->willReturn($workload); - - $registry = $this->prophesize(RegistryInterface::class); - $command = new RunHandlerCommand('task:run:handler', $registry->reveal()); - - $command->run($input->reveal(), $output->reveal()); - - $registry->run($handlerName, $workload)->shouldBeCalledTimes(1); - } -} diff --git a/tests/Unit/Command/ScheduleTaskCommandTest.php b/tests/Unit/Command/ScheduleTaskCommandTest.php deleted file mode 100644 index ccd5978..0000000 --- a/tests/Unit/Command/ScheduleTaskCommandTest.php +++ /dev/null @@ -1,96 +0,0 @@ -prophesize(SchedulerInterface::class); - $command = new ScheduleTaskCommand('task:schedule:task', $scheduler->reveal()); - - $this->assertEquals('task:schedule:task', $command->getName()); - $this->assertTrue($command->getDefinition()->hasArgument('handler')); - $this->assertTrue($command->getDefinition()->hasArgument('workload')); - } - - public function runProvider() - { - return [ - ['test-handler'], - ['test-handler', 'test-workload'], - ['test-handler-1', 'test-workload-1'], - ['test-handler', 'test-workload', '1 * * * *'], - ['test-handler', 'test-workload', '1 * * * *', '+1 week'], - ['test-handler', 'test-workload', '1 * * * *', '+1 week', 'test-key'], - ['test-handler', 'test-workload', '1 * * * *', null, 'test-key'], - ['test-handler', 'test-workload', null, null, 'test-key'], - ['test-handler', 'test-workload', null, '+1 week', 'test-key'], - ]; - } - - /** - * @dataProvider runProvider - */ - public function testRun($handler, $workload = null, $cronExpression = null, $endDateString = null, $key = null) - { - $taskBuilder = $this->prophesize(TaskBuilderInterface::class); - - $input = $this->prophesize(InputInterface::class); - $output = $this->prophesize(OutputInterface::class); - - $input->bind(Argument::any())->willReturn(true); - $input->validate()->willReturn(true); - $input->isInteractive()->willReturn(false); - $input->hasArgument('command')->willReturn(false); - - $input->getArgument('handler')->willReturn($handler); - $input->getArgument('workload')->willReturn($workload); - $input->getOption('cron-expression')->willReturn($cronExpression); - $input->getOption('end-date')->willReturn($endDateString); - $input->getOption('key')->willReturn($key); - - $scheduler = $this->prophesize(SchedulerInterface::class); - $command = new ScheduleTaskCommand('task:schedule:task', $scheduler->reveal()); - - $scheduler->createTask($handler, $workload)->shouldBeCalledTimes(1)->willReturn($taskBuilder->reveal()); - - if ($key !== null) { - $taskBuilder->setKey($key)->shouldBeCalled(); - } else { - $taskBuilder->setKey(Argument::any())->shouldNotBeCalled(); - } - if ($cronExpression !== null) { - $endDate = null; - if ($endDateString !== null) { - $endDate = new \DateTime($endDateString); - } - - $taskBuilder->cron( - $cronExpression, - Argument::type(\DateTime::class), - Argument::that( - function ($argument) use ($endDate) { - $this->assertEquals($endDate, $argument, '', 2); - - return true; - } - ) - )->shouldBeCalled() - ->willReturn($taskBuilder->reveal()); - } else { - $taskBuilder->cron(Argument::any(), Argument::any(), Argument::any())->shouldNotBeCalled() - ->willReturn($taskBuilder->reveal()); - } - $taskBuilder->schedule()->shouldBeCalledTimes(1); - - $command->run($input->reveal(), $output->reveal()); - } -} diff --git a/tests/Unit/DependencyInjection/HandlerCompilerPassTest.php b/tests/Unit/DependencyInjection/HandlerCompilerPassTest.php deleted file mode 100644 index e657ffb..0000000 --- a/tests/Unit/DependencyInjection/HandlerCompilerPassTest.php +++ /dev/null @@ -1,61 +0,0 @@ -prophesize(ContainerBuilder::class); - $definition = $this->prophesize(Definition::class); - - $containerBuilder->has(HandlerCompilerPass::REGISTRY_ID)->willReturn(true); - $containerBuilder->findDefinition(HandlerCompilerPass::REGISTRY_ID)->willReturn($definition->reveal()); - - $containerBuilder->findTaggedServiceIds(HandlerCompilerPass::HANDLER_TAG) - ->willReturn( - [ - 'id-1' => [ - [HandlerCompilerPass::HANDLER_NAME_ATTRIBUTE => 'name-1'], - ], - 'id-2' => [ - [HandlerCompilerPass::HANDLER_NAME_ATTRIBUTE => 'name-2-1'], - [HandlerCompilerPass::HANDLER_NAME_ATTRIBUTE => 'name-2-2'], - ], - ] - ); - - $compilerPass = new HandlerCompilerPass(); - $compilerPass->process($containerBuilder->reveal()); - - $definition->addMethodCall( - HandlerCompilerPass::ADD_FUNCTION_NAME, - Argument::that( - function ($arguments) { - return $arguments[0] === 'name-1' && $arguments[1]->__toString() === 'id-1'; - } - ) - )->shouldBeCalledTimes(1); - $definition->addMethodCall( - HandlerCompilerPass::ADD_FUNCTION_NAME, - Argument::that( - function ($arguments) { - return $arguments[0] === 'name-2-1' && $arguments[1]->__toString() === 'id-2'; - } - ) - )->shouldBeCalledTimes(1); - $definition->addMethodCall( - HandlerCompilerPass::ADD_FUNCTION_NAME, - Argument::that( - function ($arguments) { - return $arguments[0] === 'name-2-2' && $arguments[1]->__toString() === 'id-2'; - } - ) - )->shouldBeCalledTimes(1); - } -} diff --git a/tests/Unit/DependencyInjection/TaskCompilerPassTest.php b/tests/Unit/DependencyInjection/TaskCompilerPassTest.php deleted file mode 100644 index e77bd4d..0000000 --- a/tests/Unit/DependencyInjection/TaskCompilerPassTest.php +++ /dev/null @@ -1,70 +0,0 @@ -prophesize(ContainerBuilder::class); - $schedulerDefinition = $this->prophesize(Definition::class); - $handler1Definition = $this->prophesize(Definition::class); - $handler2Definition = $this->prophesize(Definition::class); - - $containerBuilder->has(TaskCompilerPass::SCHEDULER_ID)->willReturn(true); - $containerBuilder->getDefinition(TaskCompilerPass::SCHEDULER_ID)->willReturn($schedulerDefinition->reveal()); - $containerBuilder->getDefinition('id-1')->willReturn($handler1Definition->reveal()); - $containerBuilder->getDefinition('id-2')->willReturn($handler2Definition->reveal()); - - $containerBuilder->findTaggedServiceIds(TaskCompilerPass::INTERVAL_TAG) - ->willReturn( - [ - 'id-1' => [ - [ - TaskCompilerPass::INTERVAL_ATTRIBUTE => 'daily', - TaskCompilerPass::WORKLOAD_ATTRIBUTE => 'test-workload', - TaskCompilerPass::KEY_ATTRIBUTE => 'test-key', - ], - ], - 'id-2' => [ - [ - TaskCompilerPass::INTERVAL_ATTRIBUTE => 'daily', - TaskCompilerPass::KEY_ATTRIBUTE => 'test-key-1', - ], - [ - TaskCompilerPass::INTERVAL_ATTRIBUTE => 'daily', - TaskCompilerPass::WORKLOAD_ATTRIBUTE => 'test-workload-2', - ], - ], - ] - ); - - $handler1Definition->getTag(HandlerCompilerPass::HANDLER_TAG)->willReturn( - [[HandlerCompilerPass::HANDLER_NAME_ATTRIBUTE => 'handler-1']] - ); - $handler2Definition->getTag(HandlerCompilerPass::HANDLER_TAG)->willReturn( - [[HandlerCompilerPass::HANDLER_NAME_ATTRIBUTE => 'handler-2']] - ); - - $compilerPass = new TaskCompilerPass(); - $compilerPass->process($containerBuilder->reveal()); - - $schedulerDefinition->addMethodCall( - TaskCompilerPass::CREATE_FUNCTION_NAME, - ['handler-1', 'test-workload', 'daily', 'test-key'] - )->shouldBeCalledTimes(1); - $schedulerDefinition->addMethodCall( - TaskCompilerPass::CREATE_FUNCTION_NAME, - ['handler-2', null, 'daily', 'test-key-1'] - )->shouldBeCalledTimes(1); - $schedulerDefinition->addMethodCall( - TaskCompilerPass::CREATE_FUNCTION_NAME, - ['handler-2', 'test-workload-2', 'daily', 'handler-2_daily_s:15:"test-workload-2";'] - )->shouldBeCalledTimes(1); - } -} diff --git a/tests/Unit/EventListener/RunListenerTest.php b/tests/Unit/EventListener/RunListenerTest.php index e7c29c2..f3938b4 100644 --- a/tests/Unit/EventListener/RunListenerTest.php +++ b/tests/Unit/EventListener/RunListenerTest.php @@ -1,9 +1,18 @@ prophesize(Event::class); - $scheduler = $this->prophesize(SchedulerInterface::class); + $taskRunner = $this->prophesize(TaskRunnerInterface::class); - $listener = new RunListener($scheduler->reveal()); + $listener = new RunListener($taskRunner->reveal()); $listener->run($event->reveal()); - $scheduler->run()->shouldBeCalledTimes(1); + $taskRunner->runTasks()->shouldBeCalledTimes(1); } } diff --git a/tests/Unit/Storage/DoctrineStorageTest.php b/tests/Unit/Storage/DoctrineStorageTest.php deleted file mode 100644 index 0354584..0000000 --- a/tests/Unit/Storage/DoctrineStorageTest.php +++ /dev/null @@ -1,104 +0,0 @@ -prophesize(EntityManagerInterface::class); - $repository = $this->prophesize(TaskRepository::class); - - $storage = new DoctrineStorage($entityManager->reveal(), $repository->reveal()); - - $task = $this->prophesize(TaskInterface::class); - $task->getUuid()->willReturn($uuid); - $task->getKey()->willReturn($key); - $task->isCompleted()->willReturn($completed); - $task->getExecutionDate()->willReturn($date); - - if ($key) { - $repository->findOneBy(['key' => $key, 'completed' => false])->willReturn(null)->shouldBeCalledTimes(1); - } - - $storage->store($task->reveal()); - - $entityManager->persist( - Argument::that( - function (TaskEntity $entity) use ($date, $completed, $uuid) { - $this->assertEquals($uuid, $entity->getUuid()); - $this->assertEquals($completed, $entity->isCompleted()); - $this->assertEquals($date, $entity->getExecutionDate()); - - return true; - } - ) - )->shouldBeCalledTimes(1); - $entityManager->flush()->shouldBeCalledTimes(1); - } - - /** - * @dataProvider storeDataProvider - */ - public function testStoreTaskForKeyExists($date, $completed, $uuid, $key = null) - { - $entityManager = $this->prophesize(EntityManagerInterface::class); - $repository = $this->prophesize(TaskRepository::class); - - $storage = new DoctrineStorage($entityManager->reveal(), $repository->reveal()); - - $task = $this->prophesize(TaskInterface::class); - $task->getUuid()->willReturn($uuid); - $task->getKey()->willReturn($key); - $task->isCompleted()->willReturn($completed); - $task->getExecutionDate()->willReturn($date); - - if ($key) { - $oldTask = $this->prophesize(TaskInterface::class); - - $repository->findOneBy(['key' => $key, 'completed' => false])->willReturn($oldTask)->shouldBeCalledTimes(1); - - $entityManager->persist(Argument::any())->shouldNotBeCalled(); - $entityManager->flush()->shouldNotBeCalled(); - } else { - $entityManager->persist( - Argument::that( - function (TaskEntity $entity) use ($date, $completed, $uuid) { - $this->assertEquals($uuid, $entity->getUuid()); - $this->assertEquals($completed, $entity->isCompleted()); - $this->assertEquals($date, $entity->getExecutionDate()); - - return true; - } - ) - )->shouldBeCalledTimes(1); - $entityManager->flush()->shouldBeCalledTimes(1); - } - - $storage->store($task->reveal()); - } -} diff --git a/tests/app/TestKernel.php b/tests/app/TestKernel.php index b35d84f..ab35657 100644 --- a/tests/app/TestKernel.php +++ b/tests/app/TestKernel.php @@ -1,5 +1,14 @@