Loading package_manager/src/Stage.php +14 −4 Original line number Diff line number Diff line Loading @@ -238,6 +238,11 @@ class Stage { * call ::claim(). However, if it was created during another request, the * stage must be claimed before operations can be performed on it. * * @param int|null $timeout * (optional) How long to allow the file copying operation to run before * timing out, in seconds, or NULL to never time out. Defaults to 300 * seconds. * * @return string * Unique ID for the stage, which can be used to claim the stage before * performing other operations on it. Calling code should store this ID for Loading @@ -248,7 +253,7 @@ class Stage { * * @see ::claim() */ public function create(): string { public function create(?int $timeout = 300): string { if (!$this->isAvailable()) { throw new StageException('Cannot create a new stage because one already exists.'); } Loading @@ -270,7 +275,7 @@ class Stage { // available. $this->dispatch($event, [$this, 'markAsAvailable']); $this->beginner->begin($active_dir, $stage_dir, $event->getExcludedPaths()); $this->beginner->begin($active_dir, $stage_dir, $event->getExcludedPaths(), NULL, $timeout); $this->dispatch(new PostCreateEvent($this)); return $id; } Loading Loading @@ -313,8 +318,13 @@ class Stage { /** * Applies staged changes to the active directory. * * @param int|null $timeout * (optional) How long to allow the file copying operation to run before * timing out, in seconds, or NULL to never time out. Defaults to 600 * seconds. */ public function apply(): void { public function apply(?int $timeout = 600): void { $this->checkOwnership(); $active_dir = $this->pathLocator->getProjectRoot(); Loading @@ -331,7 +341,7 @@ class Stage { $this->tempStore->set(self::TEMPSTORE_APPLY_TIME_KEY, $this->time->getRequestTime()); $this->dispatch($event, $release_apply); $this->committer->commit($stage_dir, $active_dir, $event->getExcludedPaths()); $this->committer->commit($stage_dir, $active_dir, $event->getExcludedPaths(), NULL, $timeout); // Rebuild the container and clear all caches, to ensure that new services // are picked up. Loading package_manager/tests/modules/package_manager_bypass/src/Beginner.php +1 −1 Original line number Diff line number Diff line Loading @@ -14,7 +14,7 @@ class Beginner extends InvocationRecorderBase implements BeginnerInterface { * {@inheritdoc} */ public function begin(string $activeDir, string $stagingDir, ?array $exclusions = [], ?OutputCallbackInterface $callback = NULL, ?int $timeout = 120): void { $this->saveInvocationArguments($activeDir, $stagingDir, $exclusions); $this->saveInvocationArguments($activeDir, $stagingDir, $exclusions, $timeout); } } package_manager/tests/modules/package_manager_bypass/src/Committer.php +1 −1 Original line number Diff line number Diff line Loading @@ -31,7 +31,7 @@ class Committer extends InvocationRecorderBase implements CommitterInterface { * {@inheritdoc} */ public function commit(string $stagingDir, string $activeDir, ?array $exclusions = [], ?OutputCallbackInterface $callback = NULL, ?int $timeout = 120): void { $this->saveInvocationArguments($activeDir, $stagingDir, $exclusions); $this->saveInvocationArguments($stagingDir, $activeDir, $exclusions, $timeout); } /** Loading package_manager/tests/src/Kernel/StageTest.php +24 −0 Original line number Diff line number Diff line Loading @@ -208,6 +208,30 @@ class StageTest extends PackageManagerKernelTestBase { $stage->apply(); } /** * Tests that Composer Stager is invoked with a long timeout. */ public function testTimeouts(): void { $stage = $this->createStage(); $stage->create(420); $stage->apply(); $timeouts = [ // The beginner was given an explicit timeout. 'package_manager.beginner' => 420, // The committer should have been called with a longer timeout than // Composer Stager's default of 120 seconds. 'package_manager.committer' => 600, ]; foreach ($timeouts as $service_id => $expected_timeout) { $invocations = $this->container->get($service_id)->getInvocationArguments(); // The service should have been called with the expected timeout. $this->assertCount(1, $invocations); $this->assertSame($expected_timeout, end($invocations[0])); } } } /** Loading src/CronUpdater.php +12 −6 Original line number Diff line number Diff line Loading @@ -76,15 +76,20 @@ class CronUpdater extends Updater { /** * Handles updates during cron. * * @param int|null $timeout * (optional) How long to allow the file copying operation to run before * timing out, in seconds, or NULL to never time out. Defaults to 300 * seconds. */ public function handleCron(): void { public function handleCron(?int $timeout = 300): void { if ($this->getMode() === static::DISABLED) { return; } $next_release = $this->releaseChooser->getLatestInInstalledMinor(); if ($next_release) { $this->performUpdate($next_release->getVersion()); $this->performUpdate($next_release->getVersion(), $timeout); } } Loading @@ -93,8 +98,11 @@ class CronUpdater extends Updater { * * @param string $update_version * The version to which to update. * @param int|null $timeout * How long to allow the operation to run before timing out, in seconds, or * NULL to never time out. */ private function performUpdate(string $update_version): void { private function performUpdate(string $update_version, ?int $timeout): void { $installed_version = (new ProjectInfo('drupal'))->getInstalledVersion(); if (empty($installed_version)) { $this->logger->error('Unable to determine the current version of Drupal core.'); Loading @@ -105,9 +113,7 @@ class CronUpdater extends Updater { // handle any exceptions or validation errors consistently, and destroy the // stage regardless of whether the update succeeds. try { $this->begin([ 'drupal' => $update_version, ]); $this->begin(['drupal' => $update_version], $timeout); $this->stage(); $this->apply(); Loading Loading
package_manager/src/Stage.php +14 −4 Original line number Diff line number Diff line Loading @@ -238,6 +238,11 @@ class Stage { * call ::claim(). However, if it was created during another request, the * stage must be claimed before operations can be performed on it. * * @param int|null $timeout * (optional) How long to allow the file copying operation to run before * timing out, in seconds, or NULL to never time out. Defaults to 300 * seconds. * * @return string * Unique ID for the stage, which can be used to claim the stage before * performing other operations on it. Calling code should store this ID for Loading @@ -248,7 +253,7 @@ class Stage { * * @see ::claim() */ public function create(): string { public function create(?int $timeout = 300): string { if (!$this->isAvailable()) { throw new StageException('Cannot create a new stage because one already exists.'); } Loading @@ -270,7 +275,7 @@ class Stage { // available. $this->dispatch($event, [$this, 'markAsAvailable']); $this->beginner->begin($active_dir, $stage_dir, $event->getExcludedPaths()); $this->beginner->begin($active_dir, $stage_dir, $event->getExcludedPaths(), NULL, $timeout); $this->dispatch(new PostCreateEvent($this)); return $id; } Loading Loading @@ -313,8 +318,13 @@ class Stage { /** * Applies staged changes to the active directory. * * @param int|null $timeout * (optional) How long to allow the file copying operation to run before * timing out, in seconds, or NULL to never time out. Defaults to 600 * seconds. */ public function apply(): void { public function apply(?int $timeout = 600): void { $this->checkOwnership(); $active_dir = $this->pathLocator->getProjectRoot(); Loading @@ -331,7 +341,7 @@ class Stage { $this->tempStore->set(self::TEMPSTORE_APPLY_TIME_KEY, $this->time->getRequestTime()); $this->dispatch($event, $release_apply); $this->committer->commit($stage_dir, $active_dir, $event->getExcludedPaths()); $this->committer->commit($stage_dir, $active_dir, $event->getExcludedPaths(), NULL, $timeout); // Rebuild the container and clear all caches, to ensure that new services // are picked up. Loading
package_manager/tests/modules/package_manager_bypass/src/Beginner.php +1 −1 Original line number Diff line number Diff line Loading @@ -14,7 +14,7 @@ class Beginner extends InvocationRecorderBase implements BeginnerInterface { * {@inheritdoc} */ public function begin(string $activeDir, string $stagingDir, ?array $exclusions = [], ?OutputCallbackInterface $callback = NULL, ?int $timeout = 120): void { $this->saveInvocationArguments($activeDir, $stagingDir, $exclusions); $this->saveInvocationArguments($activeDir, $stagingDir, $exclusions, $timeout); } }
package_manager/tests/modules/package_manager_bypass/src/Committer.php +1 −1 Original line number Diff line number Diff line Loading @@ -31,7 +31,7 @@ class Committer extends InvocationRecorderBase implements CommitterInterface { * {@inheritdoc} */ public function commit(string $stagingDir, string $activeDir, ?array $exclusions = [], ?OutputCallbackInterface $callback = NULL, ?int $timeout = 120): void { $this->saveInvocationArguments($activeDir, $stagingDir, $exclusions); $this->saveInvocationArguments($stagingDir, $activeDir, $exclusions, $timeout); } /** Loading
package_manager/tests/src/Kernel/StageTest.php +24 −0 Original line number Diff line number Diff line Loading @@ -208,6 +208,30 @@ class StageTest extends PackageManagerKernelTestBase { $stage->apply(); } /** * Tests that Composer Stager is invoked with a long timeout. */ public function testTimeouts(): void { $stage = $this->createStage(); $stage->create(420); $stage->apply(); $timeouts = [ // The beginner was given an explicit timeout. 'package_manager.beginner' => 420, // The committer should have been called with a longer timeout than // Composer Stager's default of 120 seconds. 'package_manager.committer' => 600, ]; foreach ($timeouts as $service_id => $expected_timeout) { $invocations = $this->container->get($service_id)->getInvocationArguments(); // The service should have been called with the expected timeout. $this->assertCount(1, $invocations); $this->assertSame($expected_timeout, end($invocations[0])); } } } /** Loading
src/CronUpdater.php +12 −6 Original line number Diff line number Diff line Loading @@ -76,15 +76,20 @@ class CronUpdater extends Updater { /** * Handles updates during cron. * * @param int|null $timeout * (optional) How long to allow the file copying operation to run before * timing out, in seconds, or NULL to never time out. Defaults to 300 * seconds. */ public function handleCron(): void { public function handleCron(?int $timeout = 300): void { if ($this->getMode() === static::DISABLED) { return; } $next_release = $this->releaseChooser->getLatestInInstalledMinor(); if ($next_release) { $this->performUpdate($next_release->getVersion()); $this->performUpdate($next_release->getVersion(), $timeout); } } Loading @@ -93,8 +98,11 @@ class CronUpdater extends Updater { * * @param string $update_version * The version to which to update. * @param int|null $timeout * How long to allow the operation to run before timing out, in seconds, or * NULL to never time out. */ private function performUpdate(string $update_version): void { private function performUpdate(string $update_version, ?int $timeout): void { $installed_version = (new ProjectInfo('drupal'))->getInstalledVersion(); if (empty($installed_version)) { $this->logger->error('Unable to determine the current version of Drupal core.'); Loading @@ -105,9 +113,7 @@ class CronUpdater extends Updater { // handle any exceptions or validation errors consistently, and destroy the // stage regardless of whether the update succeeds. try { $this->begin([ 'drupal' => $update_version, ]); $this->begin(['drupal' => $update_version], $timeout); $this->stage(); $this->apply(); Loading