Passed
Push — develop ( d0652c...9b7b5f )
by Nikolay
06:22
created

WorkerBase::checkCountProcesses()   B

Complexity

Conditions 7
Paths 9

Size

Total Lines 30
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 18
c 0
b 0
f 0
dl 0
loc 30
rs 8.8333
cc 7
nc 9
nop 0
1
<?php
2
/*
3
 * Copyright © MIKO LLC - All Rights Reserved
4
 * Unauthorized copying of this file, via any medium is strictly prohibited
5
 * Proprietary and confidential
6
 * Written by Alexey Portnov, 9 2020
7
 */
8
9
namespace MikoPBX\Core\Workers;
10
11
use MikoPBX\Core\Asterisk\AsteriskManager;
12
use MikoPBX\Core\System\BeanstalkClient;
13
use MikoPBX\Core\System\Util;
14
use Phalcon\Di;
15
use Phalcon\Text;
16
17
abstract class WorkerBase extends Di\Injectable implements WorkerInterface
18
{
19
    protected AsteriskManager $am;
20
    protected int $maxProc = 0;
21
    public int $currentProcId = 1;
22
23
    /**
24
     * Workers shared constructor
25
     */
26
    public function __construct()
27
    {
28
        $this->checkCountProcesses();
29
        $this->savePidFile();
30
    }
31
32
    /**
33
     * Calculates how many processes have started already and kill excess or old processes
34
     */
35
    private function checkCountProcesses(): void
36
    {
37
        $activeProcesses = Util::getPidOfProcess(static::class, getmypid());
38
        if ($this->maxProc === 1) {
39
            if ( ! empty($activeProcesses)) {
40
                $killApp = Util::which('kill');
41
                // Завершаем старый процесс.
42
                Util::mwExec("{$killApp} {$activeProcesses}");
43
            }
44
        } elseif ($this->maxProc > 1) {
45
            // Лимит процессов может быть превышен. Удаление лишних процессов.
46
            $processes = explode(' ', $activeProcesses);
47
48
            // Запустим нехдостающие процессы
49
            $countProc = count($processes);
50
            while ($countProc < $this->maxProc) {
51
                Util::processPHPWorker(static::class,'start','multiStart');
52
                $countProc++;
53
            }
54
            // Получим количество лишних процессов.
55
            $countProc = count($processes) - $this->maxProc;
56
            $killApp   = Util::which('kill');
57
            // Завершим лишние
58
            while ($countProc >= 0) {
59
                if ( ! isset($processes[$countProc])) {
60
                    break;
61
                }
62
                // Завершаем старый процесс.
63
                Util::mwExec("{$killApp} {$processes[$countProc]}");
64
                $countProc--;
65
            }
66
        }
67
    }
68
69
    /**
70
     * Saves pid to pidfile
71
     */
72
    private function savePidFile(): void
73
    {
74
        $activeProcesses = Util::getPidOfProcess(static::class);
75
        file_put_contents($this->getPidFile(), $activeProcesses);
76
    }
77
78
    /**
79
     * Create PID file for worker
80
     */
81
    public function getPidFile(): string
82
    {
83
        $name = str_replace("\\", '-', static::class);
84
        return "/var/run/{$name}.pid";
85
    }
86
87
    /**
88
     * Ping callback for keep alive check
89
     *
90
     * @param BeanstalkClient $message
91
     */
92
    public function pingCallBack(BeanstalkClient $message): void
93
    {
94
        $message->reply(json_encode($message->getBody() . ':pong'));
95
    }
96
97
    /**
98
     * If it was Ping request to check worker, we answer Pong and return True
99
     *
100
     * @param $parameters
101
     *
102
     * @return bool
103
     */
104
    public function replyOnPingRequest($parameters): bool
105
    {
106
        $pingTube = $this->makePingTubeName(static::class);
107
        if ($pingTube === $parameters['UserEvent']) {
108
            $this->am->UserEvent("{$pingTube}Pong", []);
109
110
            return true;
111
        }
112
113
        return false;
114
    }
115
116
    /**
117
     * Make ping tube from classname and ping word
118
     *
119
     * @param string $workerClassName
120
     *
121
     * @return string
122
     */
123
    public function makePingTubeName(string $workerClassName): string
124
    {
125
        return Text::camelize("ping_{$workerClassName}", '\\');
126
    }
127
}