Passed
Push — typo3v9 ( 2404ee...b9b5fa )
by Tomas Norre
05:51
created

ProcessCleanUpHook::killProcess()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 4
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 8
ccs 0
cts 0
cp 0
crap 6
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace AOE\Crawler\Hooks;
6
7
/***************************************************************
8
 *  Copyright notice
9
 *
10
 *  (c) 2019 AOE GmbH <[email protected]>
11
 *
12
 *  All rights reserved
13
 *
14
 *  This script is part of the TYPO3 project. The TYPO3 project is
15
 *  free software; you can redistribute it and/or modify
16
 *  it under the terms of the GNU General Public License as published by
17
 *  the Free Software Foundation; either version 3 of the License, or
18
 *  (at your option) any later version.
19
 *
20
 *  The GNU General Public License can be found at
21
 *  http://www.gnu.org/copyleft/gpl.html.
22
 *
23
 *  This script is distributed in the hope that it will be useful,
24
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
25
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26
 *  GNU General Public License for more details.
27
 *
28
 *  This copyright notice MUST APPEAR in all copies of the script!
29
 ***************************************************************/
30
31
use AOE\Crawler\Controller\CrawlerController;
32
use AOE\Crawler\Domain\Repository\ProcessRepository;
33
use AOE\Crawler\Domain\Repository\QueueRepository;
34
use TYPO3\CMS\Core\Core\Environment;
35
use TYPO3\CMS\Core\Utility\GeneralUtility;
36
use TYPO3\CMS\Extbase\Object\ObjectManager;
37
38
/**
39
 * Class ProcessCleanUpHook
40
 * @package AOE\Crawler\Hooks
41
 */
42
class ProcessCleanUpHook
43
{
44
    /**
45
     * @var CrawlerController
46
     */
47
    private $crawlerController;
48
49
    /**
50
     * @var array
51
     */
52
    private $extensionSettings;
53
54
    /**
55
     * @var ProcessRepository
56
     */
57
    protected $processRepository;
58
59
    /**
60
     * @var QueueRepository
61
     */
62
    protected $queueRepository;
63
64 5
    public function __construct()
65
    {
66 5
        $objectManager = GeneralUtility::makeInstance(ObjectManager::class);
67 5
        $this->processRepository = $objectManager->get(ProcessRepository::class);
68 5
        $this->queueRepository = $objectManager->get(QueueRepository::class);
69 5
    }
70
71
    /**
72
     * Main function of process CleanUp Hook.
73
     *
74
     * @param CrawlerController $crawlerController Crawler Lib class
75
     *
76
     * @return void
77
     */
78
    public function crawler_init(CrawlerController $crawlerController): void
79
    {
80
        $this->crawlerController = $crawlerController;
81
        $this->extensionSettings = $this->crawlerController->extensionSettings;
82
83
        // Clean Up
84
        $this->removeActiveOrphanProcesses();
85
        $this->removeActiveProcessesOlderThanOneHour();
86
    }
87
88
    /**
89
     * Remove active processes older than one hour
90
     *
91
     * @return void
92
     */
93
    private function removeActiveProcessesOlderThanOneHour(): void
94
    {
95
        $results = $this->processRepository->getActiveProcessesOlderThanOneHour();
96
97
        if (!is_array($results)) {
0 ignored issues
show
introduced by
The condition is_array($results) is always true.
Loading history...
98
            return;
99
        }
100
        foreach ($results as $result) {
101
            $systemProcessId = (int)$result['system_process_id'];
102
            $processId = $result['process_id'];
103
            if ($systemProcessId > 1) {
104
                if ($this->doProcessStillExists($systemProcessId)) {
105
                    $this->killProcess($systemProcessId);
106
                }
107
                $this->removeProcessFromProcesslist($processId);
108
            }
109
        }
110
    }
111
112
    /**
113
     * Removes active orphan processes from process list
114
     *
115
     * @return void
116
     */
117
    private function removeActiveOrphanProcesses(): void
118
    {
119
        $results = $this->processRepository->getActiveOrphanProcesses();
120
121
        if (!is_array($results)) {
0 ignored issues
show
introduced by
The condition is_array($results) is always true.
Loading history...
122
            return;
123
        }
124
        foreach ($results as $result) {
125
            $processExists = false;
126
            $systemProcessId = (int)$result['system_process_id'];
127
            $processId = $result['process_id'];
128
            if ($systemProcessId > 1) {
129
                $dispatcherProcesses = $this->findDispatcherProcesses();
130
                if (!is_array($dispatcherProcesses) || empty($dispatcherProcesses)) {
131
                    $this->removeProcessFromProcesslist($processId);
132
                    return;
133
                }
134
                foreach ($dispatcherProcesses as $process) {
135
                    $responseArray = $this->createResponseArray($process);
136
                    if ($systemProcessId === (int)$responseArray[1]) {
137
                        $processExists = true;
138
                    };
139
                }
140
                if (!$processExists) {
141
                    $this->removeProcessFromProcesslist($processId);
142
                }
143
            }
144
        }
145
    }
146
147
    /**
148
     * Remove a process from processlist
149
     *
150
     * @param string $processId Unique process Id.
151
     *
152
     * @return void
153
     */
154 3
    private function removeProcessFromProcesslist($processId): void
155
    {
156 3
        $this->processRepository->removeByProcessId($processId);
157 3
        $this->queueRepository->unsetQueueProcessId($processId);
158 3
    }
159
160
    /**
161
     * Create response array
162
     * Convert string to array with space character as delimiter,
163
     * removes all empty records to have a cleaner array
164
     *
165
     * @param string $string String to create array from
166
     *
167
     * @return array
168
     *
169
     */
170 2
    private function createResponseArray($string)
171
    {
172 2
        $responseArray = GeneralUtility::trimExplode(' ', $string, true);
173 2
        return array_values($responseArray);
174
    }
175
176
    /**
177
     * Check if the process still exists
178
     *
179
     * @param int $pid Process id to be checked.
180
     *
181
     * @return bool
182
     * @codeCoverageIgnore
183
     */
184
    private function doProcessStillExists($pid)
185
    {
186
        $doProcessStillExists = false;
187
        if (!Environment::isWindows()) {
188
            // Not windows
189
            if (file_exists('/proc/' . $pid)) {
190
                $doProcessStillExists = true;
191
            }
192
        } else {
193
            // Windows
194
            exec('tasklist | find "' . $pid . '"', $returnArray, $returnValue);
195
            if (count($returnArray) > 0 && preg_match('/php/i', $returnValue[0])) {
196
                $doProcessStillExists = true;
197
            }
198
        }
199
        return $doProcessStillExists;
200
    }
201
202
    /**
203
     * Kills a process
204
     *
205
     * @param int $pid Process id to kill
206
     *
207
     * @return void
208
     * @codeCoverageIgnore
209
     */
210
    private function killProcess($pid): void
211
    {
212
        if (!Environment::isWindows()) {
213
            // Not windows
214
            posix_kill($pid, 9);
215
        } else {
216
            // Windows
217
            exec('taskkill /PID ' . $pid);
218
        }
219
    }
220
221
    /**
222
     * Find dispatcher processes
223
     *
224
     * @return array
225
     * @codeCoverageIgnore
226
     */
227
    private function findDispatcherProcesses()
228
    {
229
        $returnArray = [];
230
        if (!Environment::isWindows()) {
231
            // Not windows
232
            exec('ps aux | grep \'typo3 crawler:processQueue\'', $returnArray, $returnValue);
233
        } else {
234
            // Windows
235
            exec('tasklist | find \'typo3 crawler:processQueue\'', $returnArray, $returnValue);
236
        }
237
        return $returnArray;
238
    }
239
}
240