Total Complexity | 40 |
Total Lines | 273 |
Duplicated Lines | 0 % |
Changes | 2 | ||
Bugs | 0 | Features | 0 |
Complex classes like Processes often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Processes, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
16 | class Processes |
||
17 | { |
||
18 | |||
19 | /** |
||
20 | * Kills process/daemon by name |
||
21 | * |
||
22 | * @param $procName |
||
23 | * |
||
24 | * @return int|null |
||
25 | */ |
||
26 | public static function killByName($procName): ?int |
||
27 | { |
||
28 | $killallPath = Util::which('killall'); |
||
29 | |||
30 | return self::mwExec($killallPath . ' ' . escapeshellarg($procName)); |
||
31 | } |
||
32 | |||
33 | /** |
||
34 | * Executes command exec(). |
||
35 | * |
||
36 | * @param $command |
||
37 | * @param $outArr |
||
38 | * @param $retVal |
||
39 | * |
||
40 | * @return int |
||
41 | */ |
||
42 | public static function mwExec($command, &$outArr = null, &$retVal = null): int |
||
55 | } |
||
56 | |||
57 | /** |
||
58 | * Executes command exec() as background process with an execution timeout. |
||
59 | * |
||
60 | * @param $command |
||
61 | * @param int $timeout |
||
62 | * @param string $logname |
||
63 | */ |
||
64 | public static function mwExecBgWithTimeout($command, $timeout = 4, $logname = '/dev/null'): void |
||
76 | } |
||
77 | |||
78 | /** |
||
79 | * Executes multiple commands. |
||
80 | * |
||
81 | * @param $arr_cmds |
||
82 | * @param array $out |
||
83 | * @param string $logname |
||
84 | */ |
||
85 | public static function mwExecCommands($arr_cmds, &$out = [], $logname = ''): void |
||
86 | { |
||
87 | $out = []; |
||
88 | foreach ($arr_cmds as $cmd) { |
||
89 | $out[] = "$cmd;"; |
||
90 | $out_cmd = []; |
||
91 | self::mwExec($cmd, $out_cmd); |
||
92 | $out = array_merge($out, $out_cmd); |
||
93 | } |
||
94 | |||
95 | if ($logname !== '') { |
||
96 | $result = implode("\n", $out); |
||
97 | file_put_contents("/tmp/{$logname}_commands.log", $result); |
||
98 | } |
||
99 | } |
||
100 | |||
101 | /** |
||
102 | * Restart all workers in separate process, |
||
103 | * we use this method after module install or delete |
||
104 | */ |
||
105 | public static function restartAllWorkers(): void |
||
106 | { |
||
107 | $workerSafeScriptsPath = Util::getFilePathByClassName(WorkerSafeScriptsCore::class); |
||
108 | $phpPath = Util::which('php'); |
||
109 | $WorkerSafeScripts = "{$phpPath} -f {$workerSafeScriptsPath} restart > /dev/null 2> /dev/null"; |
||
110 | self::mwExec($WorkerSafeScripts); |
||
111 | } |
||
112 | |||
113 | /** |
||
114 | * Process PHP workers |
||
115 | * |
||
116 | * @param string $className |
||
117 | * @param string $paramForPHPWorker |
||
118 | * @param string $action |
||
119 | */ |
||
120 | public static function processPHPWorker( |
||
121 | string $className, |
||
122 | string $paramForPHPWorker = 'start', |
||
123 | string $action = 'restart' |
||
124 | ): void { |
||
125 | $workerPath = Util::getFilePathByClassName($className); |
||
126 | if (empty($workerPath)) { |
||
127 | return; |
||
128 | } |
||
129 | $command = "php -f {$workerPath}"; |
||
130 | $path_kill = Util::which('kill'); |
||
131 | $activeProcesses = self::getPidOfProcess($className); |
||
132 | $processes = explode(' ', $activeProcesses); |
||
133 | if (empty($processes[0])) { |
||
134 | array_shift($processes); |
||
135 | } |
||
136 | $currentProcCount = count($processes); |
||
137 | |||
138 | if ( ! class_exists($className)) { |
||
139 | return; |
||
140 | } |
||
141 | $workerObject = new $className(); |
||
142 | $neededProcCount = $workerObject->maxProc; |
||
143 | |||
144 | switch ($action) { |
||
145 | case 'restart': |
||
146 | // Stop all old workers |
||
147 | if ($activeProcesses !== '') { |
||
148 | self::mwExec("{$path_kill} SIGUSR1 {$activeProcesses} > /dev/null 2>&1 &"); |
||
149 | self::mwExecBgWithTimeout("{$path_kill} SIGTERM {$activeProcesses}", 10); |
||
150 | $currentProcCount = 0; |
||
151 | } |
||
152 | |||
153 | // Start new processes |
||
154 | while ($currentProcCount < $neededProcCount) { |
||
155 | self::mwExecBg("{$command} {$paramForPHPWorker}"); |
||
156 | $currentProcCount++; |
||
157 | } |
||
158 | |||
159 | break; |
||
160 | case 'stop': |
||
161 | if ($activeProcesses !== '') { |
||
162 | self::mwExec("{$path_kill} SIGUSR1 {$activeProcesses} > /dev/null 2>&1 &"); |
||
163 | self::mwExecBgWithTimeout("{$path_kill} SIGTERM {$activeProcesses}", 10); |
||
164 | } |
||
165 | break; |
||
166 | case 'start': |
||
167 | if ($currentProcCount === $neededProcCount) { |
||
168 | return; |
||
169 | } elseif ($neededProcCount > $currentProcCount) { |
||
170 | // Start additional processes |
||
171 | while ($currentProcCount < $neededProcCount) { |
||
172 | self::mwExecBg("{$command} {$paramForPHPWorker}"); |
||
173 | $currentProcCount++; |
||
174 | } |
||
175 | } elseif ($currentProcCount > $neededProcCount) { |
||
176 | // Find redundant processes |
||
177 | $countProc4Kill = $neededProcCount - $currentProcCount; |
||
178 | // Send SIGUSR1 command to them |
||
179 | while ($countProc4Kill >= 0) { |
||
180 | if ( ! isset($processes[$countProc4Kill])) { |
||
181 | break; |
||
182 | } |
||
183 | // Kill old processes with timeout, maybe it is soft restart and worker die without any help |
||
184 | self::mwExec("{$path_kill} SIGUSR1 {$processes[$countProc4Kill]} > /dev/null 2>&1 &"); |
||
185 | self::mwExecBgWithTimeout("{$path_kill} SIGTERM {$processes[$countProc4Kill]}", 10); |
||
186 | $countProc4Kill--; |
||
187 | } |
||
188 | } |
||
189 | break; |
||
190 | default: |
||
191 | } |
||
192 | } |
||
193 | |||
194 | /** |
||
195 | * Возвращает PID процесса по его имени. |
||
196 | * |
||
197 | * @param $name |
||
198 | * @param string $exclude |
||
199 | * |
||
200 | * @return string |
||
201 | */ |
||
202 | public static function getPidOfProcess($name, $exclude = ''): string |
||
203 | { |
||
204 | $path_ps = Util::which('ps'); |
||
205 | $path_grep = Util::which('grep'); |
||
206 | $path_awk = Util::which('awk'); |
||
207 | |||
208 | $name = addslashes($name); |
||
209 | $filter_cmd = ''; |
||
210 | if ( ! empty($exclude)) { |
||
211 | $filter_cmd = "| $path_grep -v " . escapeshellarg($exclude); |
||
212 | } |
||
213 | $out = []; |
||
214 | self::mwExec( |
||
215 | "{$path_ps} -A -o 'pid,args' {$filter_cmd} | {$path_grep} '{$name}' | {$path_grep} -v grep | {$path_awk} ' {print $1} '", |
||
216 | $out |
||
217 | ); |
||
218 | |||
219 | return trim(implode(' ', $out)); |
||
220 | } |
||
221 | |||
222 | /** |
||
223 | * Executes command exec() as background process. |
||
224 | * |
||
225 | * @param $command |
||
226 | * @param $out_file |
||
227 | * @param $sleep_time |
||
228 | */ |
||
229 | public static function mwExecBg($command, $out_file = '/dev/null', $sleep_time = 0): void |
||
243 | } |
||
244 | |||
245 | /** |
||
246 | * Manages a daemon/worker process |
||
247 | * Returns process statuses by name of it |
||
248 | * |
||
249 | * @param $cmd |
||
250 | * @param $param |
||
251 | * @param $proc_name |
||
252 | * @param $action |
||
253 | * @param $out_file |
||
254 | * |
||
255 | * @return array | bool |
||
256 | */ |
||
257 | public static function processWorker($cmd, $param, $proc_name, $action, $out_file = '/dev/null') |
||
289 | } |
||
290 | |||
291 | } |