ai_upgrade_assistant-0.2.0-alpha2/src/Service/UpdateCronService.php
src/Service/UpdateCronService.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\Queue\QueueFactory;
use Drupal\Core\Queue\QueueInterface;
use Drupal\Core\Datetime\DrupalDateTime;
/**
* Service for managing scheduled updates via cron.
*/
class UpdateCronService {
/**
* The queue for processing updates.
*
* @var \Drupal\Core\Queue\QueueInterface
*/
protected $queue;
/**
* The update scheduler service.
*
* @var \Drupal\ai_upgrade_assistant\Service\UpdateSchedulerService
*/
protected $scheduler;
/**
* The update monitor service.
*
* @var \Drupal\ai_upgrade_assistant\Service\UpdateMonitorService
*/
protected $monitor;
/**
* The update history service.
*
* @var \Drupal\ai_upgrade_assistant\Service\UpdateHistoryService
*/
protected $history;
/**
* The config factory.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $config;
/**
* The state service.
*
* @var \Drupal\Core\State\StateInterface
*/
protected $state;
/**
* The logger factory.
*
* @var \Drupal\Core\Logger\LoggerChannelFactoryInterface
*/
protected $loggerFactory;
/**
* The logger channel.
*
* @var \Drupal\Core\Logger\LoggerChannelInterface
*/
protected $logger;
/**
* Constructs a new UpdateCronService.
*
* @param \Drupal\Core\Queue\QueueFactory $queue_factory
* The queue factory.
* @param \Drupal\ai_upgrade_assistant\Service\UpdateSchedulerService $scheduler
* The update scheduler service.
* @param \Drupal\ai_upgrade_assistant\Service\UpdateMonitorService $monitor
* The update monitor service.
* @param \Drupal\ai_upgrade_assistant\Service\UpdateHistoryService $history
* The update history service.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory.
* @param \Drupal\Core\State\StateInterface $state
* The state service.
* @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger_factory
* The logger factory service.
*/
public function __construct(
QueueFactory $queue_factory,
UpdateSchedulerService $scheduler,
UpdateMonitorService $monitor,
UpdateHistoryService $history,
ConfigFactoryInterface $config_factory,
StateInterface $state,
LoggerChannelFactoryInterface $logger_factory
) {
$this->queue = $queue_factory->get('ai_upgrade_assistant_updates');
$this->scheduler = $scheduler;
$this->monitor = $monitor;
$this->history = $history;
$this->config = $config_factory;
$this->state = $state;
$this->loggerFactory = $logger_factory;
$this->logger = $logger_factory->get('ai_upgrade_assistant');
}
/**
* Processes scheduled updates during cron run.
*/
public function processCron() {
// Check if we're within the allowed update window
if (!$this->isWithinUpdateWindow()) {
$this->logger->info('Outside of configured update window. Skipping updates.');
return;
}
// Get scheduled updates that are ready to run
$updates = $this->scheduler->getReadyUpdates();
if (empty($updates)) {
$this->logger->info('No updates ready to be processed.');
return;
}
foreach ($updates as $update) {
// Check if we're already processing this update
if ($this->isUpdateInProgress($update)) {
continue;
}
// Queue the update for processing
$this->queueUpdate($update);
}
// Process security updates immediately if configured
$config = $this->config->get('ai_upgrade_assistant.settings');
if ($config->get('process_security_updates_immediately')) {
$this->processSecurityUpdates();
}
}
/**
* Checks if current time is within the configured update window.
*
* @return bool
* TRUE if within update window, FALSE otherwise.
*/
protected function isWithinUpdateWindow() {
$config = $this->config->get('ai_upgrade_assistant.settings');
$window_start = $config->get('update_window_start') ?: '00:00';
$window_end = $config->get('update_window_end') ?: '23:59';
$current_time = new DrupalDateTime();
$current_hour = $current_time->format('H:i');
// Handle window crossing midnight
if ($window_start > $window_end) {
return $current_hour >= $window_start || $current_hour <= $window_end;
}
return $current_hour >= $window_start && $current_hour <= $window_end;
}
/**
* Checks if an update is already in progress.
*
* @param array $update
* The update to check.
*
* @return bool
* TRUE if update is in progress, FALSE otherwise.
*/
protected function isUpdateInProgress(array $update) {
$in_progress = $this->state->get('ai_upgrade_assistant.updates_in_progress', []);
$key = $update['module_name'] . '-' . $update['to_version'];
if (isset($in_progress[$key])) {
// Check if the update has been stuck for too long
$timeout = $this->config->get('ai_upgrade_assistant.settings')
->get('update_timeout') ?: 3600; // Default 1 hour
if ((time() - $in_progress[$key]) > $timeout) {
// Clear the stuck update
unset($in_progress[$key]);
$this->state->set('ai_upgrade_assistant.updates_in_progress', $in_progress);
return FALSE;
}
return TRUE;
}
return FALSE;
}
/**
* Queues an update for processing.
*
* @param array $update
* The update to queue.
*/
protected function queueUpdate(array $update) {
// Mark update as in progress
$in_progress = $this->state->get('ai_upgrade_assistant.updates_in_progress', []);
$key = $update['module_name'] . '-' . $update['to_version'];
$in_progress[$key] = time();
$this->state->set('ai_upgrade_assistant.updates_in_progress', $in_progress);
// Record update start in history
$update_id = $this->history->recordUpdateStart(
$update['module_name'],
$update['from_version'],
$update['to_version'],
[
'complexity' => $update['complexity'] ?? 'unknown',
'security_update' => $update['security_update'] ?? FALSE,
'estimated_duration' => $update['estimated_duration'] ?? NULL,
]
);
// Add to queue
$this->queue->createItem([
'update' => $update,
'update_id' => $update_id,
]);
$this->logger->info(
'Queued update for @module from @from to @to',
[
'@module' => $update['module_name'],
'@from' => $update['from_version'],
'@to' => $update['to_version'],
]
);
}
/**
* Processes security updates immediately.
*/
protected function processSecurityUpdates() {
$security_updates = $this->monitor->getSecurityUpdates();
foreach ($security_updates as $update) {
if (!$this->isUpdateInProgress($update)) {
$this->queueUpdate($update);
}
}
}
}
