1
|
|
|
<?php |
2
|
|
|
/* |
3
|
|
|
* This file is part of PHP-Task library. |
4
|
|
|
* |
5
|
|
|
* (c) php-task |
6
|
|
|
* |
7
|
|
|
* This source file is subject to the MIT license that is bundled |
8
|
|
|
* with this source code in the file LICENSE. |
9
|
|
|
*/ |
10
|
|
|
|
11
|
|
|
namespace Task; |
12
|
|
|
|
13
|
|
|
use Psr\Log\LoggerInterface; |
14
|
|
|
use Symfony\Component\EventDispatcher\EventDispatcherInterface; |
15
|
|
|
use Task\Event\Events; |
16
|
|
|
use Task\Event\TaskEvent; |
17
|
|
|
use Task\Event\TaskFailedEvent; |
18
|
|
|
use Task\FrequentTask\FrequentTaskInterface; |
19
|
|
|
use Task\Handler\RegistryInterface; |
20
|
|
|
use Task\Storage\StorageInterface; |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* Central component which handles tasks. |
24
|
|
|
* |
25
|
|
|
* Allows to create and run tasks. |
26
|
|
|
* |
27
|
|
|
* @author Johannes Wachter <@wachterjohannes> |
28
|
|
|
*/ |
29
|
|
|
class Scheduler implements SchedulerInterface |
30
|
|
|
{ |
31
|
|
|
/** |
32
|
|
|
* @var StorageInterface |
33
|
|
|
*/ |
34
|
|
|
private $storage; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* @var RegistryInterface |
38
|
|
|
*/ |
39
|
|
|
private $registry; |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* @var TaskBuilderFactoryInterface |
43
|
|
|
*/ |
44
|
|
|
private $factory; |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* @var EventDispatcherInterface |
48
|
|
|
*/ |
49
|
|
|
private $eventDispatcher; |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* @var LoggerInterface |
53
|
|
|
*/ |
54
|
|
|
private $logger; |
55
|
|
|
|
56
|
11 |
|
public function __construct( |
57
|
|
|
StorageInterface $storage, |
58
|
|
|
RegistryInterface $registry, |
59
|
|
|
TaskBuilderFactoryInterface $factory, |
60
|
|
|
EventDispatcherInterface $eventDispatcher, |
61
|
|
|
LoggerInterface $logger = null |
62
|
|
|
) { |
63
|
11 |
|
$this->storage = $storage; |
64
|
11 |
|
$this->registry = $registry; |
65
|
11 |
|
$this->factory = $factory; |
66
|
11 |
|
$this->eventDispatcher = $eventDispatcher; |
67
|
11 |
|
$this->logger = $logger; |
68
|
11 |
|
} |
69
|
|
|
|
70
|
|
|
/** |
71
|
|
|
* {@inheritdoc} |
72
|
|
|
*/ |
73
|
1 |
|
public function createTask($handlerName, $workload = null) |
74
|
|
|
{ |
75
|
1 |
|
return $this->factory->create($this, $handlerName, $workload); |
|
|
|
|
76
|
|
|
} |
77
|
|
|
|
78
|
|
|
/** |
79
|
|
|
* {@inheritdoc} |
80
|
|
|
*/ |
81
|
4 |
|
public function createTaskAndSchedule($handlerName, $workload = null, $interval = null, $key = null) |
82
|
|
|
{ |
83
|
4 |
|
$taskBuilder = $this->createTask($handlerName, $workload); |
84
|
2 |
|
|
85
|
|
|
if ($interval) { |
|
|
|
|
86
|
|
|
$taskBuilder->{$interval}(); |
87
|
2 |
|
} |
88
|
2 |
|
|
89
|
|
|
if ($key) { |
|
|
|
|
90
|
|
|
$taskBuilder->setKey($key); |
91
|
|
|
} |
92
|
|
|
|
93
|
6 |
|
return $taskBuilder->schedule(); |
94
|
|
|
} |
95
|
|
|
|
96
|
6 |
|
/** |
97
|
4 |
|
* {@inheritdoc} |
98
|
|
|
*/ |
99
|
|
|
public function schedule(TaskInterface $task) |
100
|
|
|
{ |
101
|
|
|
if (!$this->registry->has($task->getTaskName())) { |
102
|
4 |
|
throw new \Exception($this->getNoHandlerFoundMessage($task)); |
103
|
|
|
} |
104
|
|
|
|
105
|
4 |
|
$this->storage->store($task); |
106
|
|
|
|
107
|
4 |
|
return $task; |
108
|
4 |
|
} |
109
|
|
|
|
110
|
4 |
|
/** |
111
|
|
|
* {@inheritdoc} |
112
|
4 |
|
*/ |
113
|
4 |
|
public function run() |
114
|
|
|
{ |
115
|
|
|
/** @var TaskInterface $task */ |
116
|
|
|
foreach ($this->storage->findScheduled() as $task) { |
117
|
|
|
if (!$this->registry->has($task->getTaskName())) { |
118
|
|
|
$this->warning($this->getNoHandlerFoundMessage($task)); |
119
|
|
|
continue; |
120
|
|
|
} |
121
|
4 |
|
|
122
|
|
|
$this->eventDispatcher->dispatch(Events::TASK_BEFORE, new TaskEvent($task)); |
123
|
|
|
|
124
|
4 |
|
try { |
125
|
2 |
|
$result = $this->registry->run($task->getTaskName(), $task->getWorkload()); |
126
|
2 |
|
|
127
|
6 |
|
$task->setResult($result); |
128
|
6 |
|
$task->setCompleted(); |
129
|
|
|
|
130
|
|
|
$this->storage->persist($task); |
131
|
|
|
|
132
|
|
|
$this->eventDispatcher->dispatch(Events::TASK_PASSED, new TaskEvent($task)); |
133
|
|
|
} catch (\Exception $ex) { |
134
|
|
|
// TODO set task failed. failed tasks, can be restarted by adding a flag to run command. |
135
|
|
|
|
136
|
|
|
$this->eventDispatcher->dispatch(Events::TASK_FAILED, new TaskFailedEvent($task, $ex)); |
137
|
2 |
|
|
138
|
|
|
throw $ex; |
139
|
2 |
|
} |
140
|
|
|
|
141
|
|
|
$this->eventDispatcher->dispatch(Events::TASK_AFTER, new TaskEvent($task)); |
142
|
|
|
|
143
|
|
|
// TODO move to event-dispatcher |
144
|
|
|
if ($task instanceof FrequentTaskInterface) { |
145
|
|
|
$task->scheduleNext($this); |
146
|
|
|
} |
147
|
|
|
} |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
/** |
151
|
|
|
* Returns message for "no handler found". |
152
|
|
|
* |
153
|
|
|
* @param TaskInterface $task |
154
|
|
|
* |
155
|
|
|
* @return string |
156
|
|
|
*/ |
157
|
|
|
private function getNoHandlerFoundMessage(TaskInterface $task) |
158
|
|
|
{ |
159
|
|
|
return sprintf('No handler found handler for "%s" task.', $task->getTaskName()); |
160
|
|
|
} |
161
|
|
|
|
162
|
|
|
/** |
163
|
|
|
* Write a warning into log. |
164
|
|
|
* |
165
|
|
|
* @param string $message |
166
|
|
|
*/ |
167
|
|
|
private function warning($message) |
168
|
|
|
{ |
169
|
|
|
if (null !== $this->logger) { |
170
|
|
|
return; |
171
|
|
|
} |
172
|
|
|
|
173
|
|
|
$this->logger->warning($message); |
174
|
|
|
} |
175
|
|
|
} |
176
|
|
|
|
This check looks at variables that have been passed in as parameters and are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.