Skip to content

Instantly share code, notes, and snippets.

@tdgroot
Last active August 1, 2019 08:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tdgroot/6ea43121a887dc74b03d935ab3517165 to your computer and use it in GitHub Desktop.
Save tdgroot/6ea43121a887dc74b03d935ab3517165 to your computer and use it in GitHub Desktop.
Patch file for Magento PR 22610
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