Last active
August 1, 2019 08:29
-
-
Save tdgroot/6ea43121a887dc74b03d935ab3517165 to your computer and use it in GitHub Desktop.
Patch file for Magento PR 22610
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/Process/Queue.php b/Process/Queue.php | |
index d8089457ce5b..21de61a6a8e1 100644 | |
--- a/Process/Queue.php | |
+++ b/Process/Queue.php | |
@@ -8,9 +8,9 @@ | |
use Magento\Deploy\Package\Package; | |
use Magento\Deploy\Service\DeployPackage; | |
use Magento\Framework\App\ResourceConnection; | |
-use Psr\Log\LoggerInterface; | |
use Magento\Framework\App\State as AppState; | |
use Magento\Framework\Locale\ResolverInterface as LocaleResolver; | |
+use Psr\Log\LoggerInterface; | |
/** | |
* Deployment Queue | |
@@ -159,6 +159,7 @@ public function process() | |
$packages = $this->packages; | |
while (count($packages) && $this->checkTimeout()) { | |
foreach ($packages as $name => $packageJob) { | |
+ // Unsets each member of $packages array (passed by reference) as each is executed | |
$this->assertAndExecute($name, $packages, $packageJob); | |
} | |
$this->logger->info('.'); | |
@@ -254,6 +255,7 @@ private function isCanBeParalleled() | |
* @param Package $package | |
* @return bool true on success for main process and exit for child process | |
* @SuppressWarnings(PHPMD.ExitExpression) | |
+ * @throws \RuntimeException | |
*/ | |
private function execute(Package $package) | |
{ | |
@@ -310,12 +312,36 @@ private function isDeployed(Package $package) | |
{ | |
if ($this->isCanBeParalleled()) { | |
if ($package->getState() === null) { | |
- $pid = pcntl_waitpid($this->getPid($package), $status, WNOHANG); | |
- if ($pid === $this->getPid($package)) { | |
+ $pid = $this->getPid($package); | |
+ | |
+ // When $pid comes back as null the child process for this package has not yet started; prevents both | |
+ // hanging until timeout expires (which was behaviour in 2.2.x) and the type error from strict_types | |
+ if ($pid === null) { | |
+ return false; | |
+ } | |
+ | |
+ $result = pcntl_waitpid($pid, $status, WNOHANG); | |
+ if ($result === $pid) { | |
$package->setState(Package::STATE_COMPLETED); | |
+ $exitStatus = pcntl_wexitstatus($status); | |
+ | |
+ $this->logger->info( | |
+ "Exited: " . $package->getPath() . "(status: $exitStatus)", | |
+ [ | |
+ 'process' => $package->getPath(), | |
+ 'status' => $exitStatus, | |
+ ] | |
+ ); | |
unset($this->inProgress[$package->getPath()]); | |
return pcntl_wexitstatus($status) === 0; | |
+ } else if ($result === -1) { | |
+ $errno = pcntl_errno(); | |
+ $strerror = pcntl_strerror($errno); | |
+ | |
+ throw new \RuntimeException( | |
+ "Error encountered checking child process status (PID: $pid): $strerror (errno: $errno)" | |
+ ); | |
} | |
return false; | |
} | |
@@ -352,9 +378,21 @@ private function checkTimeout() | |
public function __destruct() | |
{ | |
foreach ($this->inProgress as $package) { | |
- if (pcntl_waitpid($this->getPid($package), $status) === -1) { | |
+ $pid = $this->getPid($package); | |
+ $this->logger->info( | |
+ "Reaping child process: {$package->getPath()} (PID: $pid)", | |
+ [ | |
+ 'process' => $package->getPath(), | |
+ 'pid' => $pid, | |
+ ] | |
+ ); | |
+ | |
+ if (pcntl_waitpid($pid, $status) === -1) { | |
+ $errno = pcntl_errno(); | |
+ $strerror = pcntl_strerror($errno); | |
+ | |
throw new \RuntimeException( | |
- 'Error while waiting for package deployed: ' . $this->getPid($package) . '; Status: ' . $status | |
+ "Error encountered waiting for child process (PID: $pid): $strerror (errno: $errno)" | |
); | |
} | |
} | |
diff --git a/Process/Queue.php b/Process/Queue.php | |
index 21de61a6a8e1..131e0ae80fb2 100644 | |
--- a/Process/Queue.php | |
+++ b/Process/Queue.php | |
@@ -335,7 +335,7 @@ private function isDeployed(Package $package) | |
unset($this->inProgress[$package->getPath()]); | |
return pcntl_wexitstatus($status) === 0; | |
- } else if ($result === -1) { | |
+ } elseif ($result === -1) { | |
$errno = pcntl_errno(); | |
$strerror = pcntl_strerror($errno); | |
diff --git a/Process/Queue.php b/Process/Queue.php | |
index 131e0ae80fb2..1b3944a884e4 100644 | |
--- a/Process/Queue.php | |
+++ b/Process/Queue.php | |
@@ -3,6 +3,8 @@ | |
* Copyright © Magento, Inc. All rights reserved. | |
* See COPYING.txt for license details. | |
*/ | |
+declare(strict_types=1); | |
+ | |
namespace Magento\Deploy\Process; | |
use Magento\Deploy\Package\Package; | |
@@ -125,6 +127,8 @@ public function __construct( | |
} | |
/** | |
+ * Adds deployment package. | |
+ * | |
* @param Package $package | |
* @param Package[] $dependencies | |
* @return bool true on success | |
@@ -140,6 +144,8 @@ public function add(Package $package, array $dependencies = []) | |
} | |
/** | |
+ * Returns packages array. | |
+ * | |
* @return Package[] | |
*/ | |
public function getPackages() | |
@@ -163,6 +169,7 @@ public function process() | |
$this->assertAndExecute($name, $packages, $packageJob); | |
} | |
$this->logger->info('.'); | |
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction | |
sleep(3); | |
foreach ($this->inProgress as $name => $package) { | |
if ($this->isDeployed($package)) { | |
@@ -183,8 +190,6 @@ public function process() | |
* @param array $packages | |
* @param array $packageJob | |
* @return void | |
- * | |
- * @SuppressWarnings(PHPMD.CyclomaticComplexity) | |
*/ | |
private function assertAndExecute($name, array & $packages, array $packageJob) | |
{ | |
@@ -208,13 +213,23 @@ private function assertAndExecute($name, array & $packages, array $packageJob) | |
} | |
} | |
} | |
+ $this->executePackage($package, $name, $packages, $dependenciesNotFinished); | |
+ } | |
+ /** | |
+ * Executes deployment package. | |
+ * | |
+ * @param Package $package | |
+ * @param string $name | |
+ * @param array $packages | |
+ * @param bool $dependenciesNotFinished | |
+ * @return void | |
+ */ | |
+ private function executePackage(Package $package, string $name, array &$packages, bool $dependenciesNotFinished) | |
+ { | |
if (!$dependenciesNotFinished | |
&& !$this->isDeployed($package) | |
- && ( | |
- $this->maxProcesses < 2 | |
- || (count($this->inProgress) < $this->maxProcesses) | |
- ) | |
+ && ($this->maxProcesses < 2 || (count($this->inProgress) < $this->maxProcesses)) | |
) { | |
unset($packages[$name]); | |
$this->execute($package); | |
@@ -235,6 +250,7 @@ private function awaitForAllProcesses() | |
} | |
} | |
$this->logger->info('.'); | |
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction | |
sleep(5); | |
} | |
if ($this->isCanBeParalleled()) { | |
@@ -244,6 +260,8 @@ private function awaitForAllProcesses() | |
} | |
/** | |
+ * Checks if can be parallel. | |
+ * | |
* @return bool | |
*/ | |
private function isCanBeParalleled() | |
@@ -252,9 +270,10 @@ private function isCanBeParalleled() | |
} | |
/** | |
+ * Executes the process. | |
+ * | |
* @param Package $package | |
* @return bool true on success for main process and exit for child process | |
- * @SuppressWarnings(PHPMD.ExitExpression) | |
* @throws \RuntimeException | |
*/ | |
private function execute(Package $package) | |
@@ -283,6 +302,7 @@ function () use ($package) { | |
); | |
if ($this->isCanBeParalleled()) { | |
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction | |
$pid = pcntl_fork(); | |
if ($pid === -1) { | |
throw new \RuntimeException('Unable to fork a new process'); | |
@@ -297,6 +317,7 @@ function () use ($package) { | |
// process child process | |
$this->inProgress = []; | |
$this->deployPackageService->deploy($package, $this->options, true); | |
+ // phpcs:ignore Magento2.Security.LanguageConstruct.ExitUsage | |
exit(0); | |
} else { | |
$this->deployPackageService->deploy($package, $this->options); | |
@@ -305,6 +326,8 @@ function () use ($package) { | |
} | |
/** | |
+ * Checks if package is deployed. | |
+ * | |
* @param Package $package | |
* @return bool | |
*/ | |
@@ -320,6 +343,7 @@ private function isDeployed(Package $package) | |
return false; | |
} | |
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction | |
$result = pcntl_waitpid($pid, $status, WNOHANG); | |
if ($result === $pid) { | |
$package->setState(Package::STATE_COMPLETED); | |
@@ -334,6 +358,7 @@ private function isDeployed(Package $package) | |
); | |
unset($this->inProgress[$package->getPath()]); | |
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction | |
return pcntl_wexitstatus($status) === 0; | |
} elseif ($result === -1) { | |
$errno = pcntl_errno(); | |
@@ -350,17 +375,19 @@ private function isDeployed(Package $package) | |
} | |
/** | |
+ * Returns process ID or null if not found. | |
+ * | |
* @param Package $package | |
* @return int|null | |
*/ | |
private function getPid(Package $package) | |
{ | |
- return isset($this->processIds[$package->getPath()]) | |
- ? $this->processIds[$package->getPath()] | |
- : null; | |
+ return $this->processIds[$package->getPath()] ?? null; | |
} | |
/** | |
+ * Checks timeout. | |
+ * | |
* @return bool | |
*/ | |
private function checkTimeout() | |
@@ -373,6 +400,7 @@ private function checkTimeout() | |
* | |
* Protect against zombie process | |
* | |
+ * @throws \RuntimeException | |
* @return void | |
*/ | |
public function __destruct() | |
@@ -387,6 +415,7 @@ public function __destruct() | |
] | |
); | |
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction | |
if (pcntl_waitpid($pid, $status) === -1) { | |
$errno = pcntl_errno(); | |
$strerror = pcntl_strerror($errno); | |
diff --git a/Process/Queue.php b/Process/Queue.php | |
index 1b3944a884e4..ca75bf1acb73 100644 | |
--- a/Process/Queue.php | |
+++ b/Process/Queue.php | |
@@ -274,6 +274,7 @@ private function isCanBeParalleled() | |
* | |
* @param Package $package | |
* @return bool true on success for main process and exit for child process | |
+ * @SuppressWarnings(PHPMD.ExitExpression) | |
* @throws \RuntimeException | |
*/ | |
private function execute(Package $package) | |
@@ -347,6 +348,7 @@ private function isDeployed(Package $package) | |
$result = pcntl_waitpid($pid, $status, WNOHANG); | |
if ($result === $pid) { | |
$package->setState(Package::STATE_COMPLETED); | |
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction | |
$exitStatus = pcntl_wexitstatus($status); | |
$this->logger->info( | |
@@ -361,7 +363,9 @@ private function isDeployed(Package $package) | |
// phpcs:ignore Magento2.Functions.DiscouragedFunction | |
return pcntl_wexitstatus($status) === 0; | |
} elseif ($result === -1) { | |
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction | |
$errno = pcntl_errno(); | |
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction | |
$strerror = pcntl_strerror($errno); | |
throw new \RuntimeException( | |
@@ -401,6 +405,7 @@ private function checkTimeout() | |
* Protect against zombie process | |
* | |
* @throws \RuntimeException | |
+ * @SuppressWarnings(PHPMD.UnusedLocalVariable) | |
* @return void | |
*/ | |
public function __destruct() | |
@@ -417,7 +422,9 @@ public function __destruct() | |
// phpcs:ignore Magento2.Functions.DiscouragedFunction | |
if (pcntl_waitpid($pid, $status) === -1) { | |
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction | |
$errno = pcntl_errno(); | |
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction | |
$strerror = pcntl_strerror($errno); | |
throw new \RuntimeException( | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment