ai_upgrade_assistant-0.2.0-alpha2/src/Service/UpdateSchedulerService.php

src/Service/UpdateSchedulerService.php
<?php

namespace Drupal\ai_upgrade_assistant\Service;

use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\State\StateInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Datetime\DrupalDateTime;

/**
 * Service for scheduling and managing automated updates.
 *
 * This service:
 * - Determines optimal update windows
 * - Schedules updates based on complexity and risk
 * - Manages update queues
 * - Tracks update history
 */
class UpdateSchedulerService {

  /**
   * The config factory service.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected $configFactory;

  /**
   * The state service.
   *
   * @var \Drupal\Core\State\StateInterface
   */
  protected $state;

  /**
   * The logger factory.
   *
   * @var \Drupal\Core\Logger\LoggerChannelFactoryInterface
   */
  protected $loggerFactory;

  /**
   * The update monitor service.
   *
   * @var \Drupal\ai_upgrade_assistant\Service\UpdateMonitorService
   */
  protected $updateMonitor;

  /**
   * The project analyzer service.
   *
   * @var \Drupal\ai_upgrade_assistant\Service\ProjectAnalyzer
   */
  protected $projectAnalyzer;

  /**
   * Constructs a new UpdateSchedulerService.
   *
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The config factory service.
   * @param \Drupal\Core\State\StateInterface $state
   *   The state service.
   * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger_factory
   *   The logger factory service.
   * @param \Drupal\ai_upgrade_assistant\Service\UpdateMonitorService $update_monitor
   *   The update monitor service.
   * @param \Drupal\ai_upgrade_assistant\Service\ProjectAnalyzer $project_analyzer
   *   The project analyzer service.
   */
  public function __construct(
    ConfigFactoryInterface $config_factory,
    StateInterface $state,
    LoggerChannelFactoryInterface $logger_factory,
    UpdateMonitorService $update_monitor,
    ProjectAnalyzer $project_analyzer
  ) {
    $this->configFactory = $config_factory;
    $this->state = $state;
    $this->loggerFactory = $logger_factory;
    $this->updateMonitor = $update_monitor;
    $this->projectAnalyzer = $project_analyzer;
  }

  /**
   * Creates an update schedule for available updates.
   *
   * @return array
   *   Scheduled updates with timing information.
   */
  public function createSchedule() {
    // Get available updates
    $updates = $this->updateMonitor->checkForUpdates();
    $advisories = $this->updateMonitor->checkSecurityAdvisories();
    
    $schedule = [];
    $config = $this->configFactory->get('ai_upgrade_assistant.settings');
    
    // Get update window settings
    $window_start = $config->get('update_window_start') ?? '01:00';
    $window_end = $config->get('update_window_end') ?? '05:00';
    $max_updates_per_window = $config->get('max_updates_per_window') ?? 3;
    
    // Sort updates by priority
    $prioritized = $this->prioritizeUpdates($updates, $advisories);
    
    // Get next available window
    $next_window = $this->getNextUpdateWindow($window_start, $window_end);
    $updates_in_window = 0;
    
    foreach ($prioritized as $module_name => $update) {
      if ($updates_in_window >= $max_updates_per_window) {
        $next_window = $this->getNextUpdateWindow($window_start, $window_end, $next_window);
        $updates_in_window = 0;
      }
      
      $schedule[$module_name] = [
        'module' => $module_name,
        'current_version' => $update['current_version'],
        'target_version' => $update['available_version'],
        'security_update' => $update['security_update'],
        'complexity' => $update['complexity'],
        'scheduled_time' => $next_window->format('Y-m-d H:i:s'),
        'estimated_duration' => $this->estimateUpdateDuration($update),
        'dependencies' => $this->getUpdateDependencies($module_name),
      ];
      
      $updates_in_window++;
    }
    
    // Store schedule
    $this->state->set('ai_upgrade_assistant.update_schedule', $schedule);
    
    return $schedule;
  }

  /**
   * Prioritizes updates based on security risk and complexity.
   *
   * @param array $updates
   *   Available updates.
   * @param array $advisories
   *   Security advisories.
   *
   * @return array
   *   Prioritized updates.
   */
  protected function prioritizeUpdates(array $updates, array $advisories) {
    $prioritized = [];
    
    // First priority: Security updates
    foreach ($updates as $name => $update) {
      if ($update['security_update']) {
        $prioritized[$name] = $update;
        unset($updates[$name]);
      }
    }
    
    // Second priority: Modules affected by advisories
    foreach ($advisories as $advisory) {
      foreach ($advisory['affected_modules'] as $module) {
        if (isset($updates[$module])) {
          $prioritized[$module] = $updates[$module];
          unset($updates[$module]);
        }
      }
    }
    
    // Third priority: Sort remaining by complexity (low to high)
    $complexity_weights = [
      'low' => 1,
      'medium' => 2,
      'high' => 3,
    ];
    
    uasort($updates, function ($a, $b) use ($complexity_weights) {
      return $complexity_weights[$a['complexity']] <=> $complexity_weights[$b['complexity']];
    });
    
    return $prioritized + $updates;
  }

  /**
   * Gets the next available update window.
   *
   * @param string $window_start
   *   Window start time (HH:MM).
   * @param string $window_end
   *   Window end time (HH:MM).
   * @param \Drupal\Core\Datetime\DrupalDateTime|null $after
   *   Optional datetime to start looking after.
   *
   * @return \Drupal\Core\Datetime\DrupalDateTime
   *   Next available window start time.
   */
  protected function getNextUpdateWindow($window_start, $window_end, DrupalDateTime $after = NULL) {
    if (!$after) {
      $after = new DrupalDateTime();
    }
    
    // Parse window times
    list($start_hour, $start_minute) = explode(':', $window_start);
    list($end_hour, $end_minute) = explode(':', $window_end);
    
    $window = new DrupalDateTime();
    $window->setTime($start_hour, $start_minute);
    
    // If current time is past today's window, move to tomorrow
    if ($after->format('H:i') > $window_end) {
      $window->modify('+1 day');
    }
    
    return $window;
  }

  /**
   * Estimates the duration of an update.
   *
   * @param array $update
   *   Update information.
   *
   * @return int
   *   Estimated duration in minutes.
   */
  protected function estimateUpdateDuration(array $update) {
    $base_duration = [
      'low' => 15,
      'medium' => 30,
      'high' => 60,
    ];
    
    $duration = $base_duration[$update['complexity']];
    
    // Add time for security updates (more testing)
    if ($update['security_update']) {
      $duration += 15;
    }
    
    // Add time for major version updates
    if ($this->isMajorVersionChange($update['current_version'], $update['target_version'])) {
      $duration *= 1.5;
    }
    
    return (int) $duration;
  }

  /**
   * Gets dependencies that need to be updated first.
   *
   * @param string $module_name
   *   Module name.
   *
   * @return array
   *   List of dependent modules that need updating.
   */
  protected function getUpdateDependencies($module_name) {
    $dependencies = [];
    $analysis = $this->projectAnalyzer->analyzeModule($module_name);
    
    if (!empty($analysis['dependencies'])) {
      foreach ($analysis['dependencies'] as $dependency) {
        $updates = $this->state->get('ai_upgrade_assistant.available_updates', []);
        if (isset($updates[$dependency])) {
          $dependencies[] = $dependency;
        }
      }
    }
    
    return $dependencies;
  }

  /**
   * Checks if update is a major version change.
   *
   * @param string $current_version
   *   Current version.
   * @param string $target_version
   *   Target version.
   *
   * @return bool
   *   TRUE if major version change.
   */
  protected function isMajorVersionChange($current_version, $target_version) {
    $current_parts = explode('.', $current_version);
    $target_parts = explode('.', $target_version);
    
    return isset($current_parts[0]) && isset($target_parts[0]) &&
      $current_parts[0] !== $target_parts[0];
  }

}

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

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