DaemonTrait::checkDaemonLimits()   B
last analyzed

Complexity

Conditions 6
Paths 8

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 22
rs 8.9457
c 0
b 0
f 0
cc 6
nc 8
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace PHPFastCGI\FastCGIDaemon;
6
7
use PHPFastCGI\FastCGIDaemon\Exception\ShutdownException;
8
9
trait DaemonTrait
10
{
11
    /**
12
     * @var bool
13
     */
14
    private $isShutdown = false;
15
16
    /**
17
     * @var string
18
     */
19
    private $shutdownMessage = '';
20
21
    /**
22
     * @var int
23
     */
24
    private $requestCount;
25
26
    /**
27
     * @var int
28
     */
29
    private $requestLimit;
30
31
    /**
32
     * @var int
33
     */
34
    private $memoryLimit;
35
36
    /**
37
     * @var bool
38
     */
39
    private $autoShutdown;
40
41
    /**
42
     * Flags the daemon for shutting down.
43
     *
44
     * @param string $message Optional shutdown message
45
     */
46
    public function flagShutdown(string $message = null): void
47
    {
48
        $this->isShutdown = true;
49
        $this->shutdownMessage = (null === $message ? 'Daemon flagged for shutdown' : $message);
50
    }
51
52
    /**
53
     * Loads to configuration from the daemon options and installs signal
54
     * handlers.
55
     *
56
     * @param DaemonOptionsInterface $daemonOptions
57
     */
58
    private function setupDaemon(DaemonOptionsInterface $daemonOptions): void
59
    {
60
        $this->requestCount = 0;
61
        $this->requestLimit = (int) $daemonOptions->getOption(DaemonOptions::REQUEST_LIMIT);
62
        $this->memoryLimit  = (int) $daemonOptions->getOption(DaemonOptions::MEMORY_LIMIT);
63
        $this->autoShutdown = (bool) $daemonOptions->getOption(DaemonOptions::AUTO_SHUTDOWN);
64
65
        $timeLimit = (int) $daemonOptions->getOption(DaemonOptions::TIME_LIMIT);
66
67
        if (DaemonOptions::NO_LIMIT !== $timeLimit) {
68
            pcntl_alarm($timeLimit);
69
        }
70
71
        $this->installSignalHandlers();
72
    }
73
74
    /**
75
     * Increments the request count and looks for application errors.
76
     *
77
     * @param int[] $statusCodes The status codes of sent responses
78
     */
79
    private function considerStatusCodes(array $statusCodes): void
80
    {
81
        $this->requestCount += count($statusCodes);
82
83
        if ($this->autoShutdown) {
84
            foreach ($statusCodes as $statusCode) {
85
                if ($statusCode >= 500 && $statusCode < 600) {
86
                    $this->flagShutdown('Automatic shutdown following status code: ' . $statusCode);
87
                    break;
88
                }
89
            }
90
        }
91
    }
92
93
    /**
94
     * Installs a handler which throws a ShutdownException upon receiving a
95
     * SIGINT or a SIGALRM.
96
     *
97
     * @throws ShutdownException On receiving a SIGINT or SIGALRM
98
     */
99
    private function installSignalHandlers(): void
100
    {
101
        declare (ticks = 1);
102
103
        pcntl_signal(SIGINT, function () {
104
            throw new ShutdownException('Daemon shutdown requested (received SIGINT)');
105
        });
106
107
        pcntl_signal(SIGALRM, function () {
108
            throw new ShutdownException('Daemon time limit reached (received SIGALRM)');
109
        });
110
    }
111
112
    /**
113
     * Checks the current PHP process against the limits specified in a daemon
114
     * options object. This function will also throw an exception if the daemon
115
     * has been flagged for shutdown.
116
     *
117
     * @throws ShutdownException When limits in the daemon options are exceeded
118
     */
119
    private function checkDaemonLimits(): void
120
    {
121
        if ($this->isShutdown) {
122
            throw new ShutdownException($this->shutdownMessage);
123
        }
124
125
        pcntl_signal_dispatch();
126
127
        if (DaemonOptions::NO_LIMIT !== $this->requestLimit) {
128
            if ($this->requestLimit <= $this->requestCount) {
129
                throw new ShutdownException('Daemon request limit reached ('.$this->requestCount.' of '.$this->requestLimit.')');
130
            }
131
        }
132
133
        if (DaemonOptions::NO_LIMIT !== $this->memoryLimit) {
134
            $memoryUsage = memory_get_usage(true);
135
136
            if ($this->memoryLimit <= $memoryUsage) {
137
                throw new ShutdownException('Daemon memory limit reached ('.$memoryUsage.' of '.$this->memoryLimit.' bytes)');
138
            }
139
        }
140
    }
141
}
142