Skip to content

Commit 52a5bde

Browse files
authored
ENGCOM-5098: Implement Better Error Handling and Fix Waits on Null PIDs in Parallel SCD Execution magento#22607
2 parents c3aba3a + 42b7ed6 commit 52a5bde

File tree

1 file changed

+51
-12
lines changed

1 file changed

+51
-12
lines changed

app/code/Magento/Deploy/Process/Queue.php

Lines changed: 51 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
use Magento\Deploy\Package\Package;
1111
use Magento\Deploy\Service\DeployPackage;
1212
use Magento\Framework\App\ResourceConnection;
13-
use Psr\Log\LoggerInterface;
1413
use Magento\Framework\App\State as AppState;
1514
use Magento\Framework\Locale\ResolverInterface as LocaleResolver;
15+
use Psr\Log\LoggerInterface;
1616

1717
/**
1818
* Deployment Queue
@@ -165,6 +165,7 @@ public function process()
165165
$packages = $this->packages;
166166
while (count($packages) && $this->checkTimeout()) {
167167
foreach ($packages as $name => $packageJob) {
168+
// Unsets each member of $packages array (passed by reference) as each is executed
168169
$this->assertAndExecute($name, $packages, $packageJob);
169170
}
170171
$this->logger->info('.');
@@ -224,12 +225,8 @@ private function assertAndExecute($name, array & $packages, array $packageJob)
224225
* @param bool $dependenciesNotFinished
225226
* @return void
226227
*/
227-
private function executePackage(
228-
Package $package,
229-
string $name,
230-
array &$packages,
231-
bool $dependenciesNotFinished
232-
) {
228+
private function executePackage(Package $package, string $name, array &$packages, bool $dependenciesNotFinished)
229+
{
233230
if (!$dependenciesNotFinished
234231
&& !$this->isDeployed($package)
235232
&& ($this->maxProcesses < 2 || (count($this->inProgress) < $this->maxProcesses))
@@ -338,14 +335,41 @@ private function isDeployed(Package $package)
338335
{
339336
if ($this->isCanBeParalleled()) {
340337
if ($package->getState() === null) {
338+
$pid = $this->getPid($package);
339+
340+
// When $pid comes back as null the child process for this package has not yet started; prevents both
341+
// hanging until timeout expires (which was behaviour in 2.2.x) and the type error from strict_types
342+
if ($pid === null) {
343+
return false;
344+
}
345+
341346
// phpcs:ignore Magento2.Functions.DiscouragedFunction
342-
$pid = pcntl_waitpid($this->getPid($package), $status, WNOHANG);
343-
if ($pid === $this->getPid($package)) {
347+
$result = pcntl_waitpid($pid, $status, WNOHANG);
348+
if ($result === $pid) {
344349
$package->setState(Package::STATE_COMPLETED);
350+
// phpcs:ignore Magento2.Functions.DiscouragedFunction
351+
$exitStatus = pcntl_wexitstatus($status);
352+
353+
$this->logger->info(
354+
"Exited: " . $package->getPath() . "(status: $exitStatus)",
355+
[
356+
'process' => $package->getPath(),
357+
'status' => $exitStatus,
358+
]
359+
);
345360

346361
unset($this->inProgress[$package->getPath()]);
347362
// phpcs:ignore Magento2.Functions.DiscouragedFunction
348363
return pcntl_wexitstatus($status) === 0;
364+
} elseif ($result === -1) {
365+
// phpcs:ignore Magento2.Functions.DiscouragedFunction
366+
$errno = pcntl_errno();
367+
// phpcs:ignore Magento2.Functions.DiscouragedFunction
368+
$strerror = pcntl_strerror($errno);
369+
370+
throw new \RuntimeException(
371+
"Error encountered checking child process status (PID: $pid): $strerror (errno: $errno)"
372+
);
349373
}
350374
return false;
351375
}
@@ -361,7 +385,7 @@ private function isDeployed(Package $package)
361385
*/
362386
private function getPid(Package $package)
363387
{
364-
return isset($this->processIds[$package->getPath()]) ?? null;
388+
return $this->processIds[$package->getPath()] ?? null;
365389
}
366390

367391
/**
@@ -380,15 +404,30 @@ private function checkTimeout()
380404
* Protect against zombie process
381405
*
382406
* @throws \RuntimeException
407+
* @SuppressWarnings(PHPMD.UnusedLocalVariable)
383408
* @return void
384409
*/
385410
public function __destruct()
386411
{
387412
foreach ($this->inProgress as $package) {
413+
$pid = $this->getPid($package);
414+
$this->logger->info(
415+
"Reaping child process: {$package->getPath()} (PID: $pid)",
416+
[
417+
'process' => $package->getPath(),
418+
'pid' => $pid,
419+
]
420+
);
421+
388422
// phpcs:ignore Magento2.Functions.DiscouragedFunction
389-
if (pcntl_waitpid($this->getPid($package), $status) === -1) {
423+
if (pcntl_waitpid($pid, $status) === -1) {
424+
// phpcs:ignore Magento2.Functions.DiscouragedFunction
425+
$errno = pcntl_errno();
426+
// phpcs:ignore Magento2.Functions.DiscouragedFunction
427+
$strerror = pcntl_strerror($errno);
428+
390429
throw new \RuntimeException(
391-
'Error while waiting for package deployed: ' . $this->getPid($package) . '; Status: ' . $status
430+
"Error encountered waiting for child process (PID: $pid): $strerror (errno: $errno)"
392431
);
393432
}
394433
}

0 commit comments

Comments
 (0)