Completed
Push — master ( f11a34...f2f137 )
by Christian
02:47
created

Runner   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 139
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 12
c 1
b 0
f 0
lcom 1
cbo 3
dl 0
loc 139
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A run() 0 18 2
A handleError() 0 18 3
B acquireLock() 0 23 5
A releaseLock() 0 5 1
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)
1 ignored issue
show
Coding Style introduced by
function run() does not seem to conform to the naming convention (^(?:is|has|should|may|supports)).

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.

Loading history...
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