Skip to content

Commit cfc46bb

Browse files
wachterjohanneschirimoya
authored andcommitted
Added process-executor which uses a process to execute tasks (#40)
* added process-executor which uses a process to execute tasks * added environment to process-executor * fixed naming and dependencies * added own interface for executor * fixed composer.json
1 parent de276da commit cfc46bb

File tree

16 files changed

+300
-11
lines changed

16 files changed

+300
-11
lines changed

.travis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ matrix:
2626
install:
2727
- composer self-update
2828
- composer update
29+
- composer info
2930

3031
before_script:
3132
- STORAGE=doctrine tests/app/console doctrine:database:create
@@ -40,5 +41,4 @@ after_script:
4041

4142
cache:
4243
directories:
43-
- "$HOME/.composer/cache"
44-
- vendor
44+
- "$HOME/.composer/cache"

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,13 @@
1111
],
1212
"require": {
1313
"php": "~5.5 || ~7.0",
14-
"php-task/php-task": "^1.1",
14+
"php-task/php-task": "dev-master",
1515
"symfony/http-kernel": "^2.6 || ^3.0",
1616
"symfony/dependency-injection": "^2.6 || ^3.0",
1717
"symfony/expression-language": "^2.6 || ^3.0",
1818
"symfony/config": "^2.6 || ^3.0",
1919
"symfony/console": "^2.6 || ^3.0",
20+
"symfony/process": "^2.6 || ^3.0",
2021
"doctrine/orm": "^2.5"
2122
},
2223
"require-dev": {

src/Command/ExecuteCommand.php

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<?php
2+
3+
/*
4+
* This file is part of php-task library.
5+
*
6+
* (c) php-task
7+
*
8+
* This source file is subject to the MIT license that is bundled
9+
* with this source code in the file LICENSE.
10+
*/
11+
12+
namespace Task\TaskBundle\Command;
13+
14+
use Symfony\Component\Console\Command\Command;
15+
use Symfony\Component\Console\Input\InputArgument;
16+
use Symfony\Component\Console\Input\InputInterface;
17+
use Symfony\Component\Console\Output\ConsoleOutputInterface;
18+
use Symfony\Component\Console\Output\OutputInterface;
19+
use Task\Handler\TaskHandlerFactoryInterface;
20+
use Task\Storage\TaskExecutionRepositoryInterface;
21+
22+
/**
23+
* Executes given execution identified by uuid.
24+
*/
25+
class ExecuteCommand extends Command
26+
{
27+
/**
28+
* @var TaskHandlerFactoryInterface
29+
*/
30+
private $handlerFactory;
31+
32+
/**
33+
* @var TaskExecutionRepositoryInterface
34+
*/
35+
private $executionRepository;
36+
37+
/**
38+
* @param string $name
39+
* @param TaskHandlerFactoryInterface $handlerFactory
40+
* @param TaskExecutionRepositoryInterface $executionRepository
41+
*/
42+
public function __construct(
43+
$name,
44+
TaskHandlerFactoryInterface $handlerFactory,
45+
TaskExecutionRepositoryInterface $executionRepository
46+
) {
47+
parent::__construct($name);
48+
49+
$this->handlerFactory = $handlerFactory;
50+
$this->executionRepository = $executionRepository;
51+
}
52+
53+
/**
54+
* {@inheritdoc}
55+
*/
56+
protected function configure()
57+
{
58+
$this->addArgument('uuid', InputArgument::REQUIRED);
59+
}
60+
61+
/**
62+
* {@inheritdoc}
63+
*/
64+
protected function execute(InputInterface $input, OutputInterface $output)
65+
{
66+
$errOutput = $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output;
67+
68+
$execution = $this->executionRepository->findByUuid($input->getArgument('uuid'));
69+
$handler = $this->handlerFactory->create($execution->getHandlerClass());
70+
71+
try {
72+
$result = $handler->handle($execution->getWorkload());
73+
} catch (\Exception $e) {
74+
$errOutput->writeln($e->__toString());
75+
76+
// Process exit-code: 0 = OK, >1 = FAIL
77+
return 1;
78+
}
79+
80+
$output->write($result);
81+
82+
return 0;
83+
}
84+
85+
/**
86+
* {@inheritdoc}
87+
*/
88+
public function isHidden()
89+
{
90+
return true;
91+
}
92+
}

src/DependencyInjection/Configuration.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,18 @@ public function getConfigTreeBuilder()
8181
->end()
8282
->end()
8383
->end()
84+
->arrayNode('executor')
85+
->addDefaultsIfNotSet()
86+
->children()
87+
->enumNode('type')->values(['inside', 'separate'])->defaultValue('inside')->end()
88+
->arrayNode('separate')
89+
->addDefaultsIfNotSet()
90+
->children()
91+
->scalarNode('console_path')->defaultValue('%kernel.root_dir%/../bin/console')->end()
92+
->end()
93+
->end()
94+
->end()
95+
->end()
8496
->arrayNode('system_tasks')
8597
->prototype('array')
8698
->children()

src/DependencyInjection/TaskExtension.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Task\TaskBundle\DependencyInjection;
1313

14+
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
1415
use Symfony\Component\Config\FileLocator;
1516
use Symfony\Component\Config\Loader\LoaderInterface;
1617
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -55,6 +56,7 @@ public function load(array $configs, ContainerBuilder $container)
5556

5657
$this->loadDoctrineAdapter($config['adapters']['doctrine'], $container);
5758
$this->loadLockingComponent($config['locking'], $container, $loader);
59+
$this->loadExecutorComponent($config['executor'], $container, $loader);
5860
}
5961

6062
/**
@@ -95,6 +97,33 @@ private function loadLockingComponent(array $config, ContainerBuilder $container
9597
$container->setParameter('task.lock.ttl', $config['ttl']);
9698
}
9799

100+
/**
101+
* Load services for executor component.
102+
*
103+
* @param array $config
104+
* @param LoaderInterface $loader
105+
* @param ContainerBuilder $container
106+
*/
107+
private function loadExecutorComponent(array $config, ContainerBuilder $container, LoaderInterface $loader)
108+
{
109+
$loader->load('executor/' . $config['type'] . '.xml');
110+
$container->setAlias('task.executor', 'task.executor.' . $config['type']);
111+
112+
if (!array_key_exists($config['type'], $config)) {
113+
return;
114+
}
115+
116+
foreach ($config[$config['type']] as $key => $value) {
117+
$container->setParameter('task.executor.' . $key, $value);
118+
}
119+
120+
if (!file_exists($container->getParameter('task.executor.console_path'))) {
121+
throw new InvalidConfigurationException(
122+
'Console file does not exists! Given in "task.executor.seperate.console".'
123+
);
124+
}
125+
}
126+
98127
/**
99128
* Find storage aliases and related ids.
100129
*
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
/*
4+
* This file is part of php-task library.
5+
*
6+
* (c) php-task
7+
*
8+
* This source file is subject to the MIT license that is bundled
9+
* with this source code in the file LICENSE.
10+
*/
11+
12+
namespace Task\TaskBundle\Executor;
13+
14+
/**
15+
* Exception wrapper which transports the serialized exception from console to the runner.
16+
*/
17+
class SeparateProcessException extends \Exception
18+
{
19+
/**
20+
* @var string
21+
*/
22+
private $errorOutput;
23+
24+
/**
25+
* @param string $errorOutput
26+
*/
27+
public function __construct($errorOutput)
28+
{
29+
$this->errorOutput = $errorOutput;
30+
}
31+
32+
/**
33+
* {@inheritdoc}
34+
*/
35+
public function __toString()
36+
{
37+
return $this->errorOutput;
38+
}
39+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
3+
/*
4+
* This file is part of php-task library.
5+
*
6+
* (c) php-task
7+
*
8+
* This source file is subject to the MIT license that is bundled
9+
* with this source code in the file LICENSE.
10+
*/
11+
12+
namespace Task\TaskBundle\Executor;
13+
14+
use Symfony\Component\Process\ProcessBuilder;
15+
use Task\Execution\TaskExecutionInterface;
16+
use Task\Executor\ExecutorInterface;
17+
18+
/**
19+
* Uses a separate process to start the executions via console-command.
20+
*/
21+
class SeparateProcessExecutor implements ExecutorInterface
22+
{
23+
/**
24+
* @var string
25+
*/
26+
private $consolePath;
27+
28+
/**
29+
* @var string
30+
*/
31+
private $environment;
32+
33+
/**
34+
* @param string $consolePath
35+
* @param string $environment
36+
*/
37+
public function __construct($consolePath, $environment)
38+
{
39+
$this->consolePath = $consolePath;
40+
$this->environment = $environment;
41+
}
42+
43+
/**
44+
* {@inheritdoc}
45+
*/
46+
public function execute(TaskExecutionInterface $execution)
47+
{
48+
$process = ProcessBuilder::create(
49+
[$this->consolePath, 'task:execute', $execution->getUuid(), '-e ' . $this->environment]
50+
)->getProcess();
51+
52+
$process->run();
53+
54+
if (!$process->isSuccessful()) {
55+
throw new SeparateProcessException($process->getErrorOutput());
56+
}
57+
58+
return $process->getOutput();
59+
}
60+
}

src/Resources/config/command.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@
1919
<tag name="console.command"/>
2020
</service>
2121

22+
<service id="task.command.executor" class="Task\TaskBundle\Command\ExecuteCommand">
23+
<argument type="string">task:execute</argument>
24+
<argument type="service" id="task.handler.factory"/>
25+
<argument type="service" id="task.storage.task_execution"/>
26+
27+
<tag name="console.command"/>
28+
</service>
29+
2230
<service id="task.command.schedule_task" class="Task\TaskBundle\Command\ScheduleTaskCommand">
2331
<argument type="string">task:schedule</argument>
2432
<argument type="service" id="task.scheduler"/>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" ?>
2+
<container xmlns="http://symfony.com/schema/dic/services"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
5+
<services>
6+
<service id="task.executor.inside" class="Task\Executor\InsideProcessExecutor">
7+
<argument type="service" id="task.handler.factory"/>
8+
</service>
9+
</services>
10+
</container>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?xml version="1.0" ?>
2+
<container xmlns="http://symfony.com/schema/dic/services"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
5+
<services>
6+
<service id="task.executor.separate" class="Task\TaskBundle\Executor\SeparateProcessExecutor">
7+
<argument type="string">%task.executor.console_path%</argument>
8+
<argument type="string">%kernel.environment%%</argument>
9+
</service>
10+
</services>
11+
</container>

src/Resources/config/scheduler.xml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,18 @@
1616
<argument type="collection"/>
1717
</service>
1818

19-
<service id="task.runner" class="Task\Runner\TaskRunner">
19+
<service id="task.runner.execution_finder" class="Task\Runner\PendingExecutionFinder">
2020
<argument type="service" id="task.storage.task_execution"/>
2121
<argument type="service" id="task.handler.factory"/>
2222
<argument type="service" id="task.lock"/>
23-
<argument type="service" id="event_dispatcher"/>
2423
<argument type="service" id="logger" on-invalid="ignore"/>
2524
</service>
25+
26+
<service id="task.runner" class="Task\Runner\TaskRunner">
27+
<argument type="service" id="task.storage.task_execution"/>
28+
<argument type="service" id="task.runner.execution_finder"/>
29+
<argument type="service" id="task.executor"/>
30+
<argument type="service" id="event_dispatcher"/>
31+
</service>
2632
</services>
2733
</container>

tests/Functional/BootstrapTest.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,16 @@ public function testBootstrap()
3737
case 'array':
3838
$this->assertInstanceOf(ArrayTaskRepository::class, $taskRepository);
3939
$this->assertInstanceOf(ArrayTaskExecutionRepository::class, $taskExecutionRepository);
40+
4041
break;
4142
case 'doctrine':
4243
$this->assertInstanceOf(TaskRepository::class, $taskRepository);
4344
$this->assertInstanceOf(TaskExecutionRepository::class, $taskExecutionRepository);
45+
4446
break;
4547
default:
4648
$this->fail('storage not supported');
49+
4750
break;
4851
}
4952
}

0 commit comments

Comments
 (0)