• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tomasnorre / crawler / 11237471329

08 Oct 2024 02:20PM UTC coverage: 68.586% (-1.3%) from 69.862%
11237471329

push

github

web-flow
ci: Update coveralls workflow (#1109)

1834 of 2674 relevant lines covered (68.59%)

3.37 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

16.67
/Classes/Hooks/ProcessCleanUpHook.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace AOE\Crawler\Hooks;
6

7
/*
8
 * (c) 2005-2021 AOE GmbH <dev@aoe.com>
9
 * (c) 2021-     Tomas Norre Mikkelsen <tomasnorre@gmail.com>
10
 *
11
 * This file is part of the TYPO3 Crawler Extension.
12
 *
13
 * It is free software; you can redistribute it and/or modify it under
14
 * the terms of the GNU General Public License, either version 2
15
 * of the License, or any later version.
16
 *
17
 * For the full copyright and license information, please read the
18
 * LICENSE.txt file that was distributed with this source code.
19
 *
20
 * The TYPO3 project - inspiring people to share!
21
 */
22

23
use AOE\Crawler\Domain\Repository\ProcessRepository;
24
use AOE\Crawler\Domain\Repository\QueueRepository;
25
use TYPO3\CMS\Core\Core\Environment;
26
use TYPO3\CMS\Core\Utility\GeneralUtility;
27

28
/**
29
 * @internal since v9.2.5
30
 */
31
class ProcessCleanUpHook implements CrawlerHookInterface
32
{
33
    protected ProcessRepository $processRepository;
34
    protected QueueRepository $queueRepository;
35

36
    public function __construct()
37
    {
38
        $this->processRepository = GeneralUtility::makeInstance(ProcessRepository::class);
5✔
39
        $this->queueRepository = GeneralUtility::makeInstance(QueueRepository::class);
5✔
40
    }
41

42
    public function crawler_init(): void
43
    {
44
        // Clean Up
45
        $this->removeActiveOrphanProcesses();
×
46
        $this->removeActiveProcessesOlderThanOneHour();
×
47
    }
48

49
    /**
50
     * Remove a process from processlist
51
     *
52
     * @param string $processId Unique process Id.
53
     */
54
    public function removeProcessFromProcesslist($processId): void
55
    {
56
        $this->processRepository->removeByProcessId($processId);
3✔
57
        $this->queueRepository->unsetQueueProcessId($processId);
3✔
58
    }
59

60
    /**
61
     * Create response array
62
     * Convert string to array with space character as delimiter,
63
     * removes all empty records to have a cleaner array
64
     *
65
     * @param string $string String to create array from
66
     *
67
     * @return array
68
     */
69
    public function createResponseArray($string)
70
    {
71
        $responseArray = GeneralUtility::trimExplode(' ', $string, true);
2✔
72
        return array_values($responseArray);
2✔
73
    }
74

75
    /**
76
     * Remove active processes older than one hour
77
     */
78
    private function removeActiveProcessesOlderThanOneHour(): void
79
    {
80
        $results = $this->processRepository->getActiveProcessesOlderThanOneHour();
×
81

82
        if (!is_array($results)) {
×
83
            return;
×
84
        }
85
        foreach ($results as $result) {
×
86
            $systemProcessId = (int) $result['system_process_id'];
×
87
            $processId = $result['process_id'];
×
88
            if ($systemProcessId > 1) {
×
89
                if ($this->doProcessStillExists($systemProcessId)) {
×
90
                    $this->killProcess($systemProcessId);
×
91
                }
92
                $this->removeProcessFromProcesslist($processId);
×
93
            }
94
        }
95
    }
96

97
    /**
98
     * Removes active orphan processes from process list
99
     */
100
    private function removeActiveOrphanProcesses(): void
101
    {
102
        $results = $this->processRepository->getActiveOrphanProcesses();
×
103

104
        if (!is_array($results)) {
×
105
            return;
×
106
        }
107
        foreach ($results as $result) {
×
108
            $processExists = false;
×
109
            $systemProcessId = (int) $result['system_process_id'];
×
110
            $processId = $result['process_id'];
×
111
            if ($systemProcessId > 1) {
×
112
                $dispatcherProcesses = $this->findDispatcherProcesses();
×
113
                if (!is_array($dispatcherProcesses) || empty($dispatcherProcesses)) {
×
114
                    $this->removeProcessFromProcesslist($processId);
×
115
                    return;
×
116
                }
117
                foreach ($dispatcherProcesses as $process) {
×
118
                    $responseArray = $this->createResponseArray($process);
×
119
                    if ($systemProcessId === (int) $responseArray[1]) {
×
120
                        $processExists = true;
×
121
                    }
122
                }
123
                if (!$processExists) {
×
124
                    $this->removeProcessFromProcesslist($processId);
×
125
                }
126
            }
127
        }
128
    }
129

130
    /**
131
     * Check if the process still exists
132
     *
133
     * @param int $pid Process id to be checked.
134
     *
135
     * @return bool
136
     * @codeCoverageIgnore
137
     */
138
    private function doProcessStillExists($pid)
139
    {
140
        $doProcessStillExists = false;
141
        if (!Environment::isWindows()) {
142
            // Not windows
143
            if (file_exists('/proc/' . $pid)) {
144
                $doProcessStillExists = true;
145
            }
146
        } else {
147
            // Windows
148
            exec('tasklist | find "' . $pid . '"', $returnArray, $returnValue);
149
            if (count($returnArray) > 0 && stripos($returnArray[0], 'php') !== false) {
150
                $doProcessStillExists = true;
151
            }
152
        }
153
        return $doProcessStillExists;
154
    }
155

156
    /**
157
     * Kills a process
158
     *
159
     * @param int $pid Process id to kill
160
     *
161
     * @codeCoverageIgnore
162
     */
163
    private function killProcess($pid): void
164
    {
165
        if (!Environment::isWindows()) {
166
            // Not windows
167
            posix_kill($pid, 9);
168
        } else {
169
            // Windows
170
            exec('taskkill /PID ' . $pid);
171
        }
172
    }
173

174
    /**
175
     * Find dispatcher processes
176
     *
177
     * @return array
178
     * @codeCoverageIgnore
179
     */
180
    private function findDispatcherProcesses()
181
    {
182
        $returnArray = [];
183
        if (!Environment::isWindows()) {
184
            // Not windows
185
            if (exec('which ps')) {
186
                // ps command is defined
187
                exec('ps aux | grep \'typo3 crawler:processQueue\'', $returnArray, $returnValue);
188
            } else {
189
                trigger_error(
190
                    'Crawler is unable to locate the ps command to clean up orphaned crawler processes.',
191
                    E_USER_WARNING
192
                );
193
            }
194
        } else {
195
            // Windows
196
            exec('tasklist | find \'typo3 crawler:processQueue\'', $returnArray, $returnValue);
197
        }
198
        return $returnArray;
199
    }
200
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc