Mercurial > hg > isophonics-drupal-site
diff core/lib/Drupal/Core/Cron.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | 1fec387a4317 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/lib/Drupal/Core/Cron.php Wed Nov 29 16:09:58 2017 +0000 @@ -0,0 +1,240 @@ +<?php + +namespace Drupal\Core; + +use Drupal\Component\Utility\Timer; +use Drupal\Core\Extension\ModuleHandlerInterface; +use Drupal\Core\Queue\QueueWorkerManagerInterface; +use Drupal\Core\Queue\RequeueException; +use Drupal\Core\State\StateInterface; +use Drupal\Core\Lock\LockBackendInterface; +use Drupal\Core\Queue\QueueFactory; +use Drupal\Core\Session\AnonymousUserSession; +use Drupal\Core\Session\AccountSwitcherInterface; +use Drupal\Core\Queue\SuspendQueueException; +use Psr\Log\LoggerInterface; +use Psr\Log\NullLogger; + +/** + * The Drupal core Cron service. + */ +class Cron implements CronInterface { + + /** + * The module handler service. + * + * @var \Drupal\Core\Extension\ModuleHandlerInterface + */ + protected $moduleHandler; + + /** + * The lock service. + * + * @var \Drupal\Core\Lock\LockBackendInterface + */ + protected $lock; + + /** + * The queue service. + * + * @var \Drupal\Core\Queue\QueueFactory + */ + protected $queueFactory; + + /** + * The state service. + * + * @var \Drupal\Core\State\StateInterface + */ + protected $state; + + /** + * The account switcher service. + * + * @var \Drupal\Core\Session\AccountSwitcherInterface + */ + protected $accountSwitcher; + + /** + * A logger instance. + * + * @var \Psr\Log\LoggerInterface + */ + protected $logger; + + /** + * The queue plugin manager. + * + * @var \Drupal\Core\Queue\QueueWorkerManagerInterface + */ + protected $queueManager; + + /** + * Constructs a cron object. + * + * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler + * The module handler + * @param \Drupal\Core\Lock\LockBackendInterface $lock + * The lock service. + * @param \Drupal\Core\Queue\QueueFactory $queue_factory + * The queue service. + * @param \Drupal\Core\State\StateInterface $state + * The state service. + * @param \Drupal\Core\Session\AccountSwitcherInterface $account_switcher + * The account switching service. + * @param \Psr\Log\LoggerInterface $logger + * A logger instance. + * @param \Drupal\Core\Queue\QueueWorkerManagerInterface $queue_manager + * The queue plugin manager. + */ + public function __construct(ModuleHandlerInterface $module_handler, LockBackendInterface $lock, QueueFactory $queue_factory, StateInterface $state, AccountSwitcherInterface $account_switcher, LoggerInterface $logger, QueueWorkerManagerInterface $queue_manager) { + $this->moduleHandler = $module_handler; + $this->lock = $lock; + $this->queueFactory = $queue_factory; + $this->state = $state; + $this->accountSwitcher = $account_switcher; + $this->logger = $logger; + $this->queueManager = $queue_manager; + } + + /** + * {@inheritdoc} + */ + public function run() { + // Allow execution to continue even if the request gets cancelled. + @ignore_user_abort(TRUE); + + // Force the current user to anonymous to ensure consistent permissions on + // cron runs. + $this->accountSwitcher->switchTo(new AnonymousUserSession()); + + // Try to allocate enough time to run all the hook_cron implementations. + drupal_set_time_limit(240); + + $return = FALSE; + + // Try to acquire cron lock. + if (!$this->lock->acquire('cron', 900.0)) { + // Cron is still running normally. + $this->logger->warning('Attempting to re-run cron while it is already running.'); + } + else { + $this->invokeCronHandlers(); + $this->setCronLastTime(); + + // Release cron lock. + $this->lock->release('cron'); + + // Return TRUE so other functions can check if it did run successfully + $return = TRUE; + } + + // Process cron queues. + $this->processQueues(); + + // Restore the user. + $this->accountSwitcher->switchBack(); + + return $return; + } + + /** + * Records and logs the request time for this cron invocation. + */ + protected function setCronLastTime() { + // Record cron time. + $this->state->set('system.cron_last', REQUEST_TIME); + $this->logger->notice('Cron run completed.'); + } + + /** + * Processes cron queues. + */ + protected function processQueues() { + // Grab the defined cron queues. + foreach ($this->queueManager->getDefinitions() as $queue_name => $info) { + if (isset($info['cron'])) { + // Make sure every queue exists. There is no harm in trying to recreate + // an existing queue. + $this->queueFactory->get($queue_name)->createQueue(); + + $queue_worker = $this->queueManager->createInstance($queue_name); + $end = time() + (isset($info['cron']['time']) ? $info['cron']['time'] : 15); + $queue = $this->queueFactory->get($queue_name); + $lease_time = isset($info['cron']['time']) ?: NULL; + while (time() < $end && ($item = $queue->claimItem($lease_time))) { + try { + $queue_worker->processItem($item->data); + $queue->deleteItem($item); + } + catch (RequeueException $e) { + // The worker requested the task be immediately requeued. + $queue->releaseItem($item); + } + catch (SuspendQueueException $e) { + // If the worker indicates there is a problem with the whole queue, + // release the item and skip to the next queue. + $queue->releaseItem($item); + + watchdog_exception('cron', $e); + + // Skip to the next queue. + continue 2; + } + catch (\Exception $e) { + // In case of any other kind of exception, log it and leave the item + // in the queue to be processed again later. + watchdog_exception('cron', $e); + } + } + } + } + } + + /** + * Invokes any cron handlers implementing hook_cron. + */ + protected function invokeCronHandlers() { + $module_previous = ''; + + // If detailed logging isn't enabled, don't log individual execution times. + $time_logging_enabled = \Drupal::config('system.cron')->get('logging'); + $logger = $time_logging_enabled ? $this->logger : new NullLogger(); + + // Iterate through the modules calling their cron handlers (if any): + foreach ($this->moduleHandler->getImplementations('cron') as $module) { + + if (!$module_previous) { + $logger->notice('Starting execution of @module_cron().', [ + '@module' => $module, + ]); + } + else { + $logger->notice('Starting execution of @module_cron(), execution of @module_previous_cron() took @time.', [ + '@module' => $module, + '@module_previous' => $module_previous, + '@time' => Timer::read('cron_' . $module_previous) . 'ms', + ]); + } + Timer::start('cron_' . $module); + + // Do not let an exception thrown by one module disturb another. + try { + $this->moduleHandler->invoke($module, 'cron'); + } + catch (\Exception $e) { + watchdog_exception('cron', $e); + } + + Timer::stop('cron_' . $module); + $module_previous = $module; + } + if ($module_previous) { + $logger->notice('Execution of @module_previous_cron() took @time.', [ + '@module_previous' => $module_previous, + '@time' => Timer::read('cron_' . $module_previous) . 'ms', + ]); + } + } + +}