1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* This file is part of tenside/core. |
5
|
|
|
* |
6
|
|
|
* (c) Christian Schiffler <[email protected]> |
7
|
|
|
* |
8
|
|
|
* For the full copyright and license information, please view the LICENSE |
9
|
|
|
* file that was distributed with this source code. |
10
|
|
|
* |
11
|
|
|
* This project is provided in good faith and hope to be usable by anyone. |
12
|
|
|
* |
13
|
|
|
* @package tenside/core |
14
|
|
|
* @author Christian Schiffler <[email protected]> |
15
|
|
|
* @copyright 2015 Christian Schiffler <[email protected]> |
16
|
|
|
* @license https://github.com/tenside/core/blob/master/LICENSE MIT |
17
|
|
|
* @link https://github.com/tenside/core |
18
|
|
|
* @filesource |
19
|
|
|
*/ |
20
|
|
|
|
21
|
|
|
namespace Tenside\Core\Task; |
22
|
|
|
|
23
|
|
|
use Psr\Log\LoggerInterface; |
24
|
|
|
use Symfony\Component\Filesystem\LockHandler; |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* This class runs a task. |
28
|
|
|
*/ |
29
|
|
|
class Runner |
30
|
|
|
{ |
31
|
|
|
/** |
32
|
|
|
* The task to be run. |
33
|
|
|
* |
34
|
|
|
* @var Task |
35
|
|
|
*/ |
36
|
|
|
private $task; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* The lock handler. |
40
|
|
|
* |
41
|
|
|
* @var LockHandler |
42
|
|
|
*/ |
43
|
|
|
private $lock; |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* The logger in use. |
47
|
|
|
* |
48
|
|
|
* @var LoggerInterface |
49
|
|
|
*/ |
50
|
|
|
private $logger; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* The shutdown error handler shall be executed. |
54
|
|
|
* |
55
|
|
|
* @var bool |
56
|
|
|
*/ |
57
|
|
|
private $shutdownHandlerActive; |
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* Create a new instance. |
61
|
|
|
* |
62
|
|
|
* @param Task $task The task to be run. |
63
|
|
|
* |
64
|
|
|
* @param LockHandler $lock The lock file to use. |
65
|
|
|
* |
66
|
|
|
* @param LoggerInterface $logger The logger to use. |
67
|
|
|
*/ |
68
|
|
|
public function __construct(Task $task, LockHandler $lock, LoggerInterface $logger) |
69
|
|
|
{ |
70
|
|
|
$this->task = $task; |
71
|
|
|
$this->lock = $lock; |
72
|
|
|
$this->logger = $logger; |
73
|
|
|
register_shutdown_function([$this, 'handleError'], $this->task); |
74
|
|
|
} |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* Run the task. |
78
|
|
|
* |
79
|
|
|
* @param string $logfile The log file to use. |
80
|
|
|
* |
81
|
|
|
* @return bool |
82
|
|
|
*/ |
83
|
|
|
public function run($logfile) |
|
|
|
|
84
|
|
|
{ |
85
|
|
|
$this->shutdownHandlerActive = true; |
86
|
|
|
$this->acquireLock(); |
87
|
|
|
|
88
|
|
|
try { |
89
|
|
|
$this->task->perform($logfile); |
90
|
|
|
} catch (\Exception $exception) { |
91
|
|
|
$this->logger->error($exception->getMessage()); |
92
|
|
|
$this->logger->error($this->task->getOutput()); |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
$this->releaseLock(); |
96
|
|
|
|
97
|
|
|
$this->shutdownHandlerActive = false; |
98
|
|
|
|
99
|
|
|
return Task::STATE_FINISHED === $this->task->getStatus(); |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* Called upon PHP shutdown. |
104
|
|
|
* |
105
|
|
|
* @return void |
106
|
|
|
*/ |
107
|
|
|
public function handleError() |
108
|
|
|
{ |
109
|
|
|
if (!$this->shutdownHandlerActive) { |
110
|
|
|
return; |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
$error = error_get_last(); |
114
|
|
|
|
115
|
|
|
if ($error['type'] === E_ERROR) { |
116
|
|
|
$message = sprintf('Error: "%s" in %s on %s', $error['message'], $error['file'], $error['line']); |
117
|
|
|
$this->task->markError(); |
118
|
|
|
$this->task->addOutput($message); |
119
|
|
|
$this->logger->error($message); |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
// Ensure to release the lock. |
123
|
|
|
$this->releaseLock(); |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
/** |
127
|
|
|
* Acquire the lock. |
128
|
|
|
* |
129
|
|
|
* @return void |
130
|
|
|
* |
131
|
|
|
* @throws \RuntimeException When the lock could not be acquired. |
132
|
|
|
*/ |
133
|
|
|
private function acquireLock() |
134
|
|
|
{ |
135
|
|
|
$this->logger->info('Acquire lock file.'); |
136
|
|
|
|
137
|
|
|
if (!$this->lock->lock()) { |
138
|
|
|
$locked = false; |
139
|
|
|
$retry = 3; |
140
|
|
|
// Try up to 3 times to acquire with short delay in between. |
141
|
|
|
while ($retry > 0) { |
142
|
|
|
usleep(1000); |
143
|
|
|
if ($locked = $this->lock->lock()) { |
144
|
|
|
break; |
145
|
|
|
} |
146
|
|
|
$retry--; |
147
|
|
|
} |
148
|
|
|
if (!$locked) { |
149
|
|
|
$this->logger->error('Could not acquire lock file.'); |
150
|
|
|
throw new \RuntimeException( |
151
|
|
|
'Another task appears to be running. If this is not the case, please remove the lock file.' |
152
|
|
|
); |
153
|
|
|
} |
154
|
|
|
} |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
/** |
158
|
|
|
* Release the lock. |
159
|
|
|
* |
160
|
|
|
* @return void |
161
|
|
|
*/ |
162
|
|
|
private function releaseLock() |
163
|
|
|
{ |
164
|
|
|
$this->logger->info('Release lock file.'); |
165
|
|
|
$this->lock->release(); |
166
|
|
|
} |
167
|
|
|
} |
168
|
|
|
|
This check examines a number of code elements and verifies that they conform to the given naming conventions.
You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.