Commit 9da7e4cd authored by alexpott's avatar alexpott

Issue #2169267 by damiankloip: Replace drupal_cron_run() with a Cron service.

parent fde84e2a
......@@ -98,6 +98,9 @@ services:
config.typed:
class: Drupal\Core\Config\TypedConfigManager
arguments: ['@config.storage', '@config.storage.schema', '@cache.config']
cron:
class: Drupal\Core\Cron
arguments: ['@module_handler', '@lock', '@queue', '@state']
database:
class: Drupal\Core\Database\Connection
factory_class: Drupal\Core\Database\Database
......
......@@ -3177,96 +3177,6 @@ function drupal_page_set_cache(Response $response, Request $request) {
}
}
/**
* Executes a cron run when called.
*
* Do not call this function from a test. Use $this->cronRun() instead.
*
* @return
* TRUE if cron ran successfully.
*/
function drupal_cron_run() {
// Allow execution to continue even if the request gets canceled.
@ignore_user_abort(TRUE);
// Prevent session information from being saved while cron is running.
$original_session_saving = drupal_save_session();
drupal_save_session(FALSE);
// Force the current user to anonymous to ensure consistent permissions on
// cron runs.
$original_user = $GLOBALS['user'];
$GLOBALS['user'] = drupal_anonymous_user();
// Try to allocate enough time to run all the hook_cron implementations.
drupal_set_time_limit(240);
$return = FALSE;
// Grab the defined cron queues.
$queues = \Drupal::moduleHandler()->invokeAll('queue_info');
drupal_alter('queue_info', $queues);
// Try to acquire cron lock.
if (!lock()->acquire('cron', 240.0)) {
// Cron is still running normally.
watchdog('cron', 'Attempting to re-run cron while it is already running.', array(), WATCHDOG_WARNING);
}
else {
// Make sure every queue exists. There is no harm in trying to recreate an
// existing queue.
foreach ($queues as $queue_name => $info) {
if (isset($info['cron'])) {
\Drupal::queue($queue_name)->createQueue();
}
}
// Iterate through the modules calling their cron handlers (if any):
foreach (\Drupal::moduleHandler()->getImplementations('cron') as $module) {
// Do not let an exception thrown by one module disturb another.
try {
module_invoke($module, 'cron');
}
catch (Exception $e) {
watchdog_exception('cron', $e);
}
}
// Record cron time.
\Drupal::state()->set('system.cron_last', REQUEST_TIME);
watchdog('cron', 'Cron run completed.', array(), WATCHDOG_NOTICE);
// Release cron lock.
lock()->release('cron');
// Return TRUE so other functions can check if it did run successfully
$return = TRUE;
}
foreach ($queues as $queue_name => $info) {
if (isset($info['cron'])) {
$callback = $info['worker callback'];
$end = time() + (isset($info['cron']['time']) ? $info['cron']['time'] : 15);
$queue = \Drupal::queue($queue_name);
while (time() < $end && ($item = $queue->claimItem())) {
try {
call_user_func_array($callback, array($item->data));
$queue->deleteItem($item);
}
catch (Exception $e) {
// In case of exception log it and leave the item in the queue
// to be processed again later.
watchdog_exception('cron', $e);
}
}
}
}
// Restore the user.
$GLOBALS['user'] = $original_user;
drupal_save_session($original_session_saving);
return $return;
}
/**
* This function is kept only for backward compatibility.
*
......
......@@ -2179,7 +2179,7 @@ function install_finished(&$install_state) {
// Run cron to populate update status tables (if available) so that users
// will be warned if they've installed an out of date Drupal version.
// Will also trigger indexing of profile-supplied content or feeds.
drupal_cron_run();
\Drupal::service('cron')->run();
// Save a snapshot of the initially installed configuration.
$active = \Drupal::service('config.storage');
......
<?php
/**
* @file
* Contains \Drupal\Core\Cron.
*/
namespace Drupal\Core;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\KeyValueStore\StateInterface;
use Drupal\Core\Lock\LockBackendInterface;
use Drupal\Core\Queue\QueueFactory;
use Drupal\Core\Session\UserSession;
/**
* 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\KeyValueStore\StateInterface
*/
protected $state;
/**
* 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\KeyValueStore\StateInterface $state
* The state service.
*/
public function __construct(ModuleHandlerInterface $module_handler, LockBackendInterface $lock, QueueFactory $queue_factory, StateInterface $state) {
$this->moduleHandler = $module_handler;
$this->lock = $lock;
$this->queueFactory = $queue_factory;
$this->state = $state;
}
/**
* {@inheritdoc}
*/
public function run() {
// Allow execution to continue even if the request gets cancelled.
@ignore_user_abort(TRUE);
// Prevent session information from being saved while cron is running.
$original_session_saving = drupal_save_session();
drupal_save_session(FALSE);
// Force the current user to anonymous to ensure consistent permissions on
// cron runs.
// @todo This currently does not work, as it will not affect the current
// user being injected into services.
$original_user = $GLOBALS['user'];
$GLOBALS['user'] = new UserSession();
// Try to allocate enough time to run all the hook_cron implementations.
drupal_set_time_limit(240);
$return = FALSE;
// Grab the defined cron queues.
$queues = $this->moduleHandler->invokeAll('queue_info');
$this->moduleHandler->alter('queue_info', $queues);
// Try to acquire cron lock.
if (!$this->lock->acquire('cron', 240.0)) {
// Cron is still running normally.
watchdog('cron', 'Attempting to re-run cron while it is already running.', array(), WATCHDOG_WARNING);
}
else {
// Make sure every queue exists. There is no harm in trying to recreate an
// existing queue.
foreach ($queues as $queue_name => $info) {
if (isset($info['cron'])) {
$this->queueFactory->get($queue_name)->createQueue();
}
}
// Iterate through the modules calling their cron handlers (if any):
foreach ($this->moduleHandler->getImplementations('cron') as $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);
}
}
// Record cron time.
$this->state->set('system.cron_last', REQUEST_TIME);
watchdog('cron', 'Cron run completed.', array(), WATCHDOG_NOTICE);
// Release cron lock.
$this->lock->release('cron');
// Return TRUE so other functions can check if it did run successfully
$return = TRUE;
}
foreach ($queues as $queue_name => $info) {
if (isset($info['cron'])) {
$callback = $info['worker callback'];
$end = time() + (isset($info['cron']['time']) ? $info['cron']['time'] : 15);
$queue = $this->queueFactory->get($queue_name);
while (time() < $end && ($item = $queue->claimItem())) {
try {
call_user_func_array($callback, array($item->data));
$queue->deleteItem($item);
}
catch (\Exception $e) {
// In case of exception log it and leave the item in the queue
// to be processed again later.
watchdog_exception('cron', $e);
}
}
}
}
// Restore the user.
// @todo This currently does not work, as it will not affect the current
// user being injected into services.
$GLOBALS['user'] = $original_user;
drupal_save_session($original_session_saving);
return $return;
}
}
<?php
/**
* Contains \Drupal\Core\CronInterface.
*/
namespace Drupal\Core;
/**
* An interface for running cron tasks.
*/
interface CronInterface {
/**
* Executes a cron run.
*
* Do not call this function from a test. Use $this->cronRun() instead.
*
* @return bool
* TRUE upon success, FALSE otherwise.
*/
public function run();
}
......@@ -69,7 +69,7 @@ function testInUse() {
))
->condition('fid', $file->id())
->execute();
drupal_cron_run();
\Drupal::service('cron')->run();
// system_cron() loads
$this->assertFileHooksCalled(array('delete'));
......
......@@ -123,7 +123,7 @@ function testRevisions() {
))
->condition('fid', $node_file_r3->id())
->execute();
drupal_cron_run();
\Drupal::service('cron')->run();
$this->assertFileNotExists($node_file_r3, 'Second file is now deleted after deleting third revision, since it is no longer being used by any other nodes.');
$this->assertFileEntryNotExists($node_file_r3, 'Second file entry is now deleted after deleting third revision, since it is no longer being used by any other nodes.');
......@@ -138,7 +138,7 @@ function testRevisions() {
))
->condition('fid', $node_file_r1->id())
->execute();
drupal_cron_run();
\Drupal::service('cron')->run();
$this->assertFileNotExists($node_file_r1, 'Original file is deleted after deleting the entire node with two revisions remaining.');
$this->assertFileEntryNotExists($node_file_r1, 'Original file entry is deleted after deleting the entire node with two revisions remaining.');
}
......
......@@ -387,7 +387,6 @@ function locale_themes_disabled($themes) {
/**
* Implements hook_cron().
*
* @see drupal_cron_run()
* @see locale_queue_info()
*/
function locale_cron() {
......
......@@ -7,13 +7,41 @@
namespace Drupal\system;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\CronInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
/**
* Controller for Cron handling.
*/
class CronController {
class CronController extends ControllerBase implements ContainerInjectionInterface {
/**
* The cron service.
*
* @var \Drupal\Core\CronInterface
*/
protected $cron;
/**
* Constructs a CronController object.
*
* @param \Drupal\Core\CronInterface $cron
* The cron service.
*/
public function __construct(CronInterface $cron) {
$this->cron = $cron;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static($container->get('cron'));
}
/**
* Run Cron once.
......@@ -22,8 +50,7 @@ class CronController {
* A Symfony response object.
*/
public function run() {
// @todo Make this an injected object.
drupal_cron_run();
$this->cron->run();
// HTTP 204 is "No content", meaning "I did what you asked and we're done."
return new Response('', 204);
......@@ -36,13 +63,14 @@ public function run() {
* A Symfony direct response object.
*/
public function runManually() {
if (drupal_cron_run()) {
drupal_set_message(t('Cron ran successfully.'));
if ($this->cron->run()) {
drupal_set_message($this->t('Cron ran successfully.'));
}
else {
drupal_set_message(t('Cron run failed.'), 'error');
drupal_set_message($this->t('Cron run failed.'), 'error');
}
return new RedirectResponse(url('admin/reports/status', array('absolute' => TRUE)));
return $this->redirect('system.status');
}
}
......@@ -8,6 +8,7 @@
namespace Drupal\system\Form;
use Drupal\Core\Config\ConfigFactory;
use Drupal\Core\CronInterface;
use Drupal\Core\KeyValueStore\StateInterface;
use Drupal\Core\Form\ConfigFormBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
......@@ -25,17 +26,27 @@ class CronForm extends ConfigFormBase {
*/
protected $state;
/**
* The cron service.
*
* @var \Drupal\Core\CronInterface
*/
protected $cron;
/**
* Constructs a CronForm object.
*
* @param \Drupal\Core\Config\ConfigFactory $config_factory
* The factory for configuration objects.
* @param \Drupal\Core\KeyValueStore\StateInterface $state
* The state keyvalue collection to use.
* The state key value store.
* @param \Drupal\Core\CronInterface $cron
* The cron service.
*/
public function __construct(ConfigFactory $config_factory, StateInterface $state) {
public function __construct(ConfigFactory $config_factory, StateInterface $state, CronInterface $cron) {
parent::__construct($config_factory);
$this->state = $state;
$this->cron = $cron;
}
/**
......@@ -44,7 +55,8 @@ public function __construct(ConfigFactory $config_factory, StateInterface $state
public static function create(ContainerInterface $container) {
return new static(
$container->get('config.factory'),
$container->get('state')
$container->get('state'),
$container->get('cron')
);
}
......@@ -110,7 +122,7 @@ public function submitForm(array &$form, array &$form_state) {
*/
public function submitCron(array &$form, array &$form_state) {
// Run cron manually from Cron form.
if (drupal_cron_run()) {
if ($this->cron->run()) {
drupal_set_message(t('Cron run successfully.'));
}
else {
......
......@@ -185,14 +185,14 @@ function hook_queue_info() {
/**
* Alter cron queue information before cron runs.
*
* Called by drupal_cron_run() to allow modules to alter cron queue settings
* Called by \Drupal\Core\Cron to allow modules to alter cron queue settings
* before any jobs are processesed.
*
* @param array $queues
* An array of cron queue information.
*
* @see hook_queue_info()
* @see drupal_cron_run()
* @see \Drupal\Core\Cron
*/
function hook_queue_info_alter(&$queues) {
// This site has many feeds so let's spend 90 seconds on each cron run
......
......@@ -2891,7 +2891,7 @@ function system_run_automated_cron() {
if (($threshold = \Drupal::config('system.cron')->get('threshold.autorun')) > 0 && \Drupal::state()->get('install_task') == 'done') {
$cron_last = \Drupal::state()->get('system.cron_last') ?: NULL;
if (!isset($cron_last) || (REQUEST_TIME - $cron_last > $threshold)) {
drupal_cron_run();
\Drupal::service('cron')->run();
}
}
}
......
......@@ -73,7 +73,7 @@ function testCreateDeletePicture() {
))
->condition('fid', $file->id())
->execute();
drupal_cron_run();
\Drupal::service('cron')->run();
// Verify that the image has been deleted.
$this->assertFalse(file_load($file->id(), TRUE), 'File was removed from the database.');
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment