Passed
Pull Request — master (#23)
by Nikolay
09:42 queued 03:08
created

WorkerBase::savePidFile()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 13
c 1
b 0
f 0
dl 0
loc 16
rs 9.8333
cc 3
nc 3
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 MikoPBX\Core\System\Processes;
15
use Phalcon\Di;
16
use Phalcon\Text;
17
18
abstract class WorkerBase extends Di\Injectable implements WorkerInterface
19
{
20
    protected AsteriskManager $am;
21
    public int $maxProc = 1;
22
    protected bool $needRestart = false;
23
24
    /**
25
     * Workers shared constructor
26
     * Do not remove FINAL there, use START function to add something
27
     */
28
    final public function __construct()
29
    {
30
        pcntl_async_signals(true);
31
        pcntl_signal(
32
            SIGUSR1,
33
            [$this, 'signalHandler']
34
        );
35
36
        $this->savePidFile();
37
    }
38
39
    /**
40
     * Saves pid to pidfile
41
     */
42
    private function savePidFile(): void
43
    {
44
        $activeProcesses = Processes::getPidOfProcess(static::class);
45
        $processes       = explode(' ', $activeProcesses);
46
        if (count($processes) === 1) {
47
            file_put_contents($this->getPidFile(), $activeProcesses);
48
        } else {
49
            $pidFilesDir = dirname($this->getPidFile());
50
            $pidFile     = $pidFilesDir . '/' . pathinfo($this->getPidFile(), PATHINFO_BASENAME);
51
            // Delete old PID files
52
            $rm = Util::which('rm');
53
            Processes::mwExec("{$rm} -rf {$pidFile}*");
54
            $i = 1;
55
            foreach ($processes as $process) {
56
                file_put_contents("{$pidFile}-{$i}.pid", $process);
57
                $i++;
58
            }
59
        }
60
    }
61
62
    /**
63
     * Create PID file for worker
64
     */
65
    public function getPidFile(): string
66
    {
67
        $name = str_replace("\\", '-', static::class);
68
69
        return "/var/run/{$name}.pid";
70
    }
71
72
    /**
73
     * Process async system signal
74
     *
75
     */
76
    public function signalHandler(): void
77
    {
78
        $this->needRestart = true;
79
    }
80
81
    /**
82
     * Ping callback for keep alive check
83
     *
84
     * @param BeanstalkClient $message
85
     */
86
    public function pingCallBack(BeanstalkClient $message): void
87
    {
88
        $message->reply(json_encode($message->getBody() . ':pong'));
89
    }
90
91
    /**
92
     * If it was Ping request to check worker, we answer Pong and return True
93
     *
94
     * @param $parameters
95
     *
96
     * @return bool
97
     */
98
    public function replyOnPingRequest($parameters): bool
99
    {
100
        $pingTube = $this->makePingTubeName(static::class);
101
        if ($pingTube === $parameters['UserEvent']) {
102
            $this->am->UserEvent("{$pingTube}Pong", []);
103
104
            return true;
105
        }
106
107
        return false;
108
    }
109
110
    /**
111
     * Makes ping tube from classname and ping word
112
     *
113
     * @param string $workerClassName
114
     *
115
     * @return string
116
     */
117
    public function makePingTubeName(string $workerClassName): string
118
    {
119
        return Text::camelize("ping_{$workerClassName}", '\\');
120
    }
121
122
    /**
123
     * Deletes old PID files
124
     */
125
    public function __destruct()
126
    {
127
        $this->savePidFile();
128
    }
129
}