PluginProbe ʕ •ᴥ•ʔ
WP STAGING – WordPress Backups, Restore, Migration & Clone / 3.0.2
WP STAGING – WordPress Backups, Restore, Migration & Clone v3.0.2
4.11.2 4.11.1 4.11.0 4.10.0 4.9.5 4.9.4 4.9.3 4.9.2 4.9.1 4.9.0 4.8.1 trunk 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.10.0 3.2.0 3.3.1 3.3.2 3.3.3 3.4.1 3.4.3 3.5.0 3.6.0 3.7.1 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.8.6 3.8.7 3.9.0 3.9.1 3.9.2 3.9.3 3.9.4 4.0.0 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.0 4.7.0 4.7.1 4.7.2 4.7.3 4.8.0
wp-staging / Framework / Traits / ResourceTrait.php
wp-staging / Framework / Traits Last commit date
ArrayableTrait.php 5 years ago BenchmarkTrait.php 3 years ago BooleanTransientTrait.php 5 years ago DatabaseSearchReplaceTrait.php 5 years ago DbRowsGeneratorTrait.php 4 years ago DeveloperTimerTrait.php 4 years ago FileScanToCacheTrait.php 3 years ago HydrateTrait.php 3 years ago MaintenanceTrait.php 5 years ago MySQLRowsGeneratorTrait.php 3 years ago NoticesTrait.php 3 years ago PropertyConstructor.php 5 years ago ResourceTrait.php 3 years ago
ResourceTrait.php
341 lines
1 <?php
2
3 namespace WPStaging\Framework\Traits;
4
5 use WPStaging\Core\WPStaging;
6
7 trait ResourceTrait
8 {
9 /** @var int|null */
10 protected $timeLimit;
11
12 protected $resourceTraitSettings;
13 protected $executionTimeLimit;
14 protected $memoryLimit;
15 protected $scriptMemoryLimit;
16
17 public static $defaultMaxExecutionTimeInSeconds = 30;
18 public static $executionTimeGapInSeconds = 5;
19
20 // Set lower maximum execution time for backup restore to avoid 504 errors in large database
21 public static $backupRestoreMaxExecutionTimeInSeconds = 10;
22
23 /** @var bool Whether this request is taking place in the context of a unit test. */
24 protected $isUnitTest;
25
26 /** @var bool If it is a unit test, whether to allow resource checks. */
27 protected $allowResourceCheckOnUnitTests;
28
29 /**
30 * @return bool
31 */
32 public function isThreshold()
33 {
34 if ($this->isUnitTest() && !$this->allowResourceCheckOnUnitTests) {
35 return false;
36 }
37
38 $isMemoryLimit = $this->isMemoryLimit();
39 $isTimeLimit = $this->isTimeLimit();
40
41 if (defined('WPSTG_DEBUG') && WPSTG_DEBUG) {
42 if ($isTimeLimit || $isMemoryLimit) {
43 \WPStaging\functions\debug_log('isThreshold: ' . wp_json_encode(['class' => __CLASS__, 'isTimeLimit' => $isTimeLimit, 'isMemoryLimit' => $isMemoryLimit], JSON_UNESCAPED_SLASHES));
44 }
45 }
46
47 if ($isMemoryLimit) {
48 return true;
49 }
50
51 if ($isTimeLimit) {
52 return true;
53 }
54
55 return false;
56 }
57
58 /**
59 * @return bool
60 */
61 public function isDatabaseRestoreThreshold()
62 {
63 return $this->isMemoryLimit() || $this->isDatabaseRestoreTimeLimit();
64 }
65
66 /**
67 * @return bool
68 */
69 public function isMaxExecutionThreshold()
70 {
71 return $this->isMemoryLimit() || $this->isMaxExecutionTimeoutLimit();
72 }
73
74 /**
75 * @see \Codeception\Module\WPLoader::_getConstants
76 *
77 * @return bool Whether this request is in the context of a unit test.
78 */
79 protected function isUnitTest()
80 {
81 if (isset($this->isUnitTest)) {
82 return $this->isUnitTest;
83 }
84
85 $this->isUnitTest = defined('WPCEPT_ISOLATED_INSTALL');
86
87 return $this->isUnitTest;
88 }
89
90 /**
91 * @return float
92 */
93 protected function getRunningTime()
94 {
95 return microtime(true) - WPStaging::$startTime;
96 }
97
98 /**
99 * @return bool
100 */
101 public function isMemoryLimit()
102 {
103 return $this->getScriptMemoryLimit() <= $this->getMemoryUsage();
104 }
105
106 /**
107 * @return bool
108 */
109 public function isTimeLimit()
110 {
111 $timeLimit = $this->findExecutionTimeLimit();
112
113 if (isset($this->timeLimit)) {
114 $timeLimit = $this->timeLimit;
115 }
116
117 return $this->getRunningTime() > $timeLimit;
118 }
119
120 /**
121 * @return bool
122 */
123 public function isDatabaseRestoreTimeLimit()
124 {
125 $timeLimit = (int)apply_filters('wpstg.resourceTrait.backupRestoreMaxExecutionTimeInSeconds', static::$backupRestoreMaxExecutionTimeInSeconds);
126 return $this->getRunningTime() > $timeLimit;
127 }
128
129 /**
130 * @return bool
131 */
132 public function isMaxExecutionTimeoutLimit()
133 {
134 return $this->getRunningTime() > $this->findExecutionTimeLimit(true);
135 }
136
137 /**
138 * Returns the maximum allowed execution time limit.
139 * The minimum needs to be 10seconds!
140 * @see https://github.com/wp-staging/wp-staging-pro/pull/1492
141 *
142 * @param bool $useMaxTimeout
143 *
144 * @return float|int
145 */
146 public function findExecutionTimeLimit($useMaxTimeout = false)
147 {
148 // Early bail: Cache
149 if (isset($this->executionTimeLimit)) {
150 return $this->executionTimeLimit;
151 }
152
153 $phpMaxExecutionTime = $this->getPhpMaxExecutionTime();
154 $cpuBoundMaxExecutionTime = $this->getCpuBoundMaxExecutionTime();
155
156 // Use the max execution time limit for CPU bound tasks like tables renaming
157 if ($useMaxTimeout) {
158 $this->executionTimeLimit = max(min($phpMaxExecutionTime - static::$executionTimeGapInSeconds, $phpMaxExecutionTime * 0.8), 10);
159
160 // Internal Use only. Allow overwriting of the max execution time limit for testing database rename task.
161 $this->executionTimeLimit = (int)apply_filters('wpstg.tests.databaseRenameTask', $this->executionTimeLimit);
162
163 return $this->executionTimeLimit;
164 }
165
166 // TODO don't overwrite when CLI / SAPI and / or add setting to not overwrite for devs
167 if (!$cpuBoundMaxExecutionTime || $cpuBoundMaxExecutionTime > static::$defaultMaxExecutionTimeInSeconds) {
168 $cpuBoundMaxExecutionTime = static::$defaultMaxExecutionTimeInSeconds;
169 }
170
171 // Never go over PHP own execution time limit, if set.
172 if ($phpMaxExecutionTime > 0) {
173 $cpuBoundMaxExecutionTime = min($phpMaxExecutionTime, $cpuBoundMaxExecutionTime);
174 }
175
176 // Set a max of 30 seconds to avoid NGINX 504 timeouts that are beyond PHP's control, with a minimum of 10 seconds
177 $this->executionTimeLimit = max(min($cpuBoundMaxExecutionTime - static::$executionTimeGapInSeconds, 30), 10);
178
179 // Allow overwriting of the max execution time limit.
180 // Important: Use a value lower than the actual PHP limit. (reduce it by 10seconds or more). Also adjust the nginx/php timeout limit
181 $this->executionTimeLimit = (int)apply_filters('wpstg.resources.executionTimeLimit', $this->executionTimeLimit);
182
183 // Allow disabling of the execution time limit
184 if ((bool)apply_filters('wpstg.resources.ignoreTimeLimit', false)) {
185 $this->executionTimeLimit = PHP_INT_MAX;
186 }
187
188 return $this->executionTimeLimit;
189 }
190
191 /**
192 * @param bool $realUsage
193 *
194 * @return int
195 */
196 protected function getMemoryUsage($realUsage = true)
197 {
198 return memory_get_usage($realUsage);
199 }
200
201 /**
202 * @param bool $realUsage
203 *
204 * @return int
205 */
206 protected function getMemoryPeakUsage($realUsage = true)
207 {
208 return memory_get_peak_usage($realUsage);
209 }
210
211 /**
212 * @return int|null
213 */
214 public function getTimeLimit()
215 {
216 if (!isset($this->timeLimit)) {
217 $this->timeLimit = $this->findExecutionTimeLimit();
218 }
219
220 return $this->timeLimit;
221 }
222
223 /**
224 * @param int|null $timeLimit
225 */
226 public function setTimeLimit($timeLimit)
227 {
228 $this->timeLimit = $timeLimit;
229 }
230
231 /**
232 * @param bool $isAllowed True to check resources on unit tests. False to not check.
233 */
234 public function resourceCheckOnUnitTests($isAllowed)
235 {
236 $this->allowResourceCheckOnUnitTests = $isAllowed;
237 }
238
239 /**
240 * Returns the current PHP memory limit in bytes.
241 *
242 * @return int
243 */
244 protected function getMaxMemoryLimit()
245 {
246 // Early bail: Cache
247 if (isset($this->memoryLimit)) {
248 return $this->memoryLimit;
249 }
250
251 $memoryLimit = wp_convert_hr_to_bytes(ini_get('memory_limit'));
252
253 // No memory limit
254 if ($memoryLimit == -1 || $memoryLimit < 0) {
255 $memoryLimit = 256 * MB_IN_BYTES;
256 }
257
258 // Allow custom overwriting
259 $this->memoryLimit = apply_filters('wpstg.resources.memoryLimit', $memoryLimit);
260
261 // Unexpected memory limit after filter and also make sure it is never below 64MB
262 if (!is_int($this->memoryLimit) || $this->memoryLimit < (64 * MB_IN_BYTES)) {
263 $this->memoryLimit = 64 * MB_IN_BYTES;
264 }
265
266 // Make sure it never exceeds 256MB
267 $this->memoryLimit = (min($this->memoryLimit, 256 * MB_IN_BYTES));
268
269 // Allow disabling the memory limit
270 if ((bool)apply_filters('wpstg.resources.ignoreMemoryLimit', false)) {
271 $this->memoryLimit = PHP_INT_MAX;
272 }
273
274 return $this->memoryLimit;
275 }
276
277 /**
278 * Returns the actual script memory limit.
279 *
280 * @return int|float The script memory limit, by definition less then the maximum memory limit.
281 */
282 protected function getScriptMemoryLimit()
283 {
284 // Early bail: Cache
285 if (isset($this->scriptMemoryLimit)) {
286 return $this->scriptMemoryLimit;
287 }
288
289 // 80% of max memory limit
290 return $this->scriptMemoryLimit = $this->getMaxMemoryLimit() * 0.8;
291 }
292
293 /**
294 * Returns the max execution time value as bound by the "CPU Load" setting.
295 *
296 * @param string|null $cpuLoadSetting Either a specific CPU Load setting to
297 * return the max execution time for, or
298 * `null` to read the current CPU Load
299 * value from the Settings.
300 *
301 * @return int The max execution time as bound by the CPU Load setting.
302 */
303 protected function getCpuBoundMaxExecutionTime($cpuLoadSetting = null)
304 {
305 // Early bail: Cache
306 if (!isset($this->resourceTraitSettings)) {
307 $this->resourceTraitSettings = json_decode(json_encode(get_option('wpstg_settings', [])));
308 }
309 if ($cpuLoadSetting === null) {
310 $cpuLoadSetting = isset($this->resourceTraitSettings->cpuLoad) ? $this->resourceTraitSettings->cpuLoad : 'medium';
311 }
312
313 $execution_gap = static::$executionTimeGapInSeconds;
314 switch ($cpuLoadSetting) {
315 case 'low':
316 $cpuBoundMaxExecutionTime = 10 + $execution_gap;
317 break;
318 case 'medium':
319 default:
320 $cpuBoundMaxExecutionTime = 20 + $execution_gap;
321 break;
322 case 'high':
323 $cpuBoundMaxExecutionTime = 25 + $execution_gap;
324 break;
325 }
326
327 return $cpuBoundMaxExecutionTime;
328 }
329
330 /**
331 * Returns the max execution time as set in PHP ini settings.
332 *
333 * @return int The PHP max execution time in seconds. Note that `0` and `-1` would
334 * both indicate there is no time limit set.
335 */
336 private function getPhpMaxExecutionTime()
337 {
338 return (int)ini_get('max_execution_time');
339 }
340 }
341