automatic_updates-8.x-2.x-dev/src/CronUpdateRunner.php

src/CronUpdateRunner.php
<?php

declare(strict_types=1);

namespace Drupal\automatic_updates;

use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\CronInterface;
use Drupal\Core\Utility\Error;
use Drupal\package_manager\PathLocator;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait;

/**
 * Runs updates as a detached background process after regular cron tasks.
 *
 * The update process will be started in a detached process which will continue
 * running after the web request has terminated. This is done after the
 * decorated cron service has been called, so regular cron tasks will always be
 * run regardless of whether there is an update available and whether an update
 * is successful.
 *
 * @internal
 *   This class implements logic specific to Automatic Updates' cron hook
 *   implementation and may be changed or removed at any time without warning.
 *   It should not be called directly, and external code should not interact
 *   with it.
 */
class CronUpdateRunner implements CronInterface, LoggerAwareInterface {

  use LoggerAwareTrait;

  /**
   * The current interface between PHP and the server.
   *
   * @var string
   */
  private static $serverApi = PHP_SAPI;

  /**
   * All automatic updates are disabled.
   *
   * @var string
   */
  public const DISABLED = 'disable';

  /**
   * Only perform automatic security updates.
   *
   * @var string
   */
  public const SECURITY = 'security';

  /**
   * All automatic updates are enabled.
   *
   * @var string
   */
  public const ALL = 'patch';

  public function __construct(
    private readonly ConfigFactoryInterface $configFactory,
    private readonly PathLocator $pathLocator,
    private readonly CronInterface $inner,
    private readonly CommandExecutor $commandExecutor,
  ) {}

  /**
   * Runs the terminal update command.
   */
  protected function runTerminalUpdateCommand(): void {
    // Use the `&` on the command line to detach this process after it is
    // started. This will allow the command to outlive the web request.
    $process = $this->commandExecutor->create('--is-from-web &');

    try {
      $pid = $this->commandExecutor->start($process);
    }
    catch (\Throwable $throwable) {
      if ($this->logger) {
        Error::logException($this->logger, $throwable, 'Unable to start background update.');
      }
    }

    if ($process->isTerminated()) {
      if ($process->getExitCode() !== 0) {
        $this->logger?->error('Background update failed: %message', [
          '%message' => $process->getErrorOutput(),
        ]);
      }
    }
    elseif (empty($pid)) {
      $this->logger?->error('Background update failed because the process did not start within 5 seconds.');
    }
  }

  /**
   * Indicates if we are currently running at the command line.
   *
   * @return bool
   *   TRUE if we are running at the command line, otherwise FALSE.
   */
  final public static function isCommandLine(): bool {
    return self::$serverApi === 'cli';
  }

  /**
   * {@inheritdoc}
   */
  public function run() {
    // Always run the cron service before we trigger the update terminal
    // command.
    $decorated_cron_succeeded = $this->inner->run();

    $method = $this->configFactory->get('automatic_updates.settings')
      ->get('unattended.method');
    // If we are configured to run updates via the web, and we're actually being
    // accessed via the web (i.e., anything that isn't the command line), go
    // ahead and try to do the update.
    if ($method === 'web' && !self::isCommandLine()) {
      $this->runTerminalUpdateCommand();
    }
    return $decorated_cron_succeeded;
  }

  /**
   * Gets the cron update mode.
   *
   * @return string
   *   The cron update mode. Will be one of the following constants:
   *   - self::DISABLED if updates during
   *     cron are entirely disabled.
   *   - self::SECURITY only security
   *     updates can be done during cron.
   *   - self::ALL if all updates are
   *     allowed during cron.
   */
  final public function getMode(): string {
    $mode = $this->configFactory->get('automatic_updates.settings')->get('unattended.level');
    return $mode ?: static::SECURITY;
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc