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: ...@@ -98,6 +98,9 @@ services:
config.typed: config.typed:
class: Drupal\Core\Config\TypedConfigManager class: Drupal\Core\Config\TypedConfigManager
arguments: ['@config.storage', '@config.storage.schema', '@cache.config'] arguments: ['@config.storage', '@config.storage.schema', '@cache.config']
cron:
class: Drupal\Core\Cron
arguments: ['@module_handler', '@lock', '@queue', '@state']
database: database:
class: Drupal\Core\Database\Connection class: Drupal\Core\Database\Connection
factory_class: Drupal\Core\Database\Database factory_class: Drupal\Core\Database\Database
......
...@@ -3177,96 +3177,6 @@ function drupal_page_set_cache(Response $response, Request $request) { ...@@ -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. * This function is kept only for backward compatibility.
* *
......
...@@ -2179,7 +2179,7 @@ function install_finished(&$install_state) { ...@@ -2179,7 +2179,7 @@ function install_finished(&$install_state) {
// Run cron to populate update status tables (if available) so that users // 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 be warned if they've installed an out of date Drupal version.
// Will also trigger indexing of profile-supplied content or feeds. // 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. // Save a snapshot of the initially installed configuration.
$active = \Drupal::service('config.storage'); $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() { ...@@ -69,7 +69,7 @@ function testInUse() {
)) ))
->condition('fid', $file->id()) ->condition('fid', $file->id())
->execute(); ->execute();
drupal_cron_run(); \Drupal::service('cron')->run();
// system_cron() loads // system_cron() loads
$this->assertFileHooksCalled(array('delete')); $this->assertFileHooksCalled(array('delete'));
......
...@@ -123,7 +123,7 @@ function testRevisions() { ...@@ -123,7 +123,7 @@ function testRevisions() {
)) ))
->condition('fid', $node_file_r3->id()) ->condition('fid', $node_file_r3->id())
->execute(); ->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->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.'); $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() { ...@@ -138,7 +138,7 @@ function testRevisions() {
)) ))
->condition('fid', $node_file_r1->id()) ->condition('fid', $node_file_r1->id())
->execute(); ->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->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.'); $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) { ...@@ -387,7 +387,6 @@ function locale_themes_disabled($themes) {
/** /**
* Implements hook_cron(). * Implements hook_cron().
* *
* @see drupal_cron_run()
* @see locale_queue_info() * @see locale_queue_info()
*/ */
function locale_cron() { function locale_cron() {
......
...@@ -7,13 +7,41 @@ ...@@ -7,13 +7,41 @@
namespace Drupal\system; 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\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
/** /**
* Controller for Cron handling. * 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. * Run Cron once.
...@@ -22,8 +50,7 @@ class CronController { ...@@ -22,8 +50,7 @@ class CronController {
* A Symfony response object. * A Symfony response object.
*/ */
public function run() { public function run() {
// @todo Make this an injected object. $this->cron->run();
drupal_cron_run();
// HTTP 204 is "No content", meaning "I did what you asked and we're done." // HTTP 204 is "No content", meaning "I did what you asked and we're done."
return new Response('', 204); return new Response('', 204);
...@@ -36,13 +63,14 @@ public function run() { ...@@ -36,13 +63,14 @@ public function run() {
* A Symfony direct response object. * A Symfony direct response object.
*/ */
public function runManually() { public function runManually() {
if (drupal_cron_run()) { if ($this->cron->run()) {
drupal_set_message(t('Cron ran successfully.')); drupal_set_message($this->t('Cron ran successfully.'));
} }
else { 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 @@ ...@@ -8,6 +8,7 @@
namespace Drupal\system\Form; namespace Drupal\system\Form;
use Drupal\Core\Config\ConfigFactory; use Drupal\Core\Config\ConfigFactory;
use Drupal\Core\CronInterface;
use Drupal\Core\KeyValueStore\StateInterface; use Drupal\Core\KeyValueStore\StateInterface;
use Drupal\Core\Form\ConfigFormBase; use Drupal\Core\Form\ConfigFormBase;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
...@@ -25,17 +26,27 @@ class CronForm extends ConfigFormBase { ...@@ -25,17 +26,27 @@ class CronForm extends ConfigFormBase {
*/ */
protected $state; protected $state;
/**
* The cron service.
*
* @var \Drupal\Core\CronInterface
*/
protected $cron;
/** /**
* Constructs a CronForm object. * Constructs a CronForm object.
* *
* @param \Drupal\Core\Config\ConfigFactory $config_factory * @param \Drupal\Core\Config\ConfigFactory $config_factory
* The factory for configuration objects. * The factory for configuration objects.
* @param \Drupal\Core\KeyValueStore\StateInterface $state * @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); parent::__construct($config_factory);
$this->state = $state; $this->state = $state;
$this->cron = $cron;
} }
/** /**
...@@ -44,7 +55,8 @@ public function __construct(ConfigFactory $config_factory, StateInterface $state ...@@ -44,7 +55,8 @@ public function __construct(ConfigFactory $config_factory, StateInterface $state
public static function create(ContainerInterface $container) { public static function create(ContainerInterface $container) {
return new static( return new static(
$container->get('config.factory'), $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) { ...@@ -110,7 +122,7 @@ public function submitForm(array &$form, array &$form_state) {
*/ */
public function submitCron(array &$form, array &$form_state) { public function submitCron(array &$form, array &$form_state) {
// Run cron manually from Cron form. // Run cron manually from Cron form.
if (drupal_cron_run()) { if ($this->cron->run()) {
drupal_set_message(t('Cron run successfully.')); drupal_set_message(t('Cron run successfully.'));
} }
else { else {
......
...@@ -185,14 +185,14 @@ function hook_queue_info() { ...@@ -185,14 +185,14 @@ function hook_queue_info() {
/** /**
* Alter cron queue information before cron runs. * 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. * before any jobs are processesed.
* *
* @param array $queues * @param array $queues
* An array of cron queue information. * An array of cron queue information.
* *
* @see hook_queue_info() * @see hook_queue_info()
* @see drupal_cron_run() * @see \Drupal\Core\Cron
*/ */
function hook_queue_info_alter(&$queues) { function hook_queue_info_alter(&$queues) {
// This site has many feeds so let's spend 90 seconds on each cron run // This site has many feeds so let's spend 90 seconds on each cron run
......
...@@ -2891,7 +2891,7 @@ function system_run_automated_cron() { ...@@ -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') { 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; $cron_last = \Drupal::state()->get('system.cron_last') ?: NULL;
if (!isset($cron_last) || (REQUEST_TIME - $cron_last > $threshold)) { if (!isset($cron_last) || (REQUEST_TIME - $cron_last > $threshold)) {
drupal_cron_run(); \Drupal::service('cron')->run();
} }
} }
} }
......
...@@ -73,7 +73,7 @@ function testCreateDeletePicture() { ...@@ -73,7 +73,7 @@ function testCreateDeletePicture() {
)) ))
->condition('fid', $file->id()) ->condition('fid', $file->id())
->execute(); ->execute();
drupal_cron_run(); \Drupal::service('cron')->run();
// Verify that the image has been deleted. // Verify that the image has been deleted.
$this->assertFalse(file_load($file->id(), TRUE), 'File was removed from the database.'); $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