Commit d0ecad65 authored by catch's avatar catch

Revert "Issue #2507031 by claudiu.cristea, dawehner, Wim Leers, mitrpaka,...

Revert "Issue #2507031 by claudiu.cristea, dawehner, Wim Leers, mitrpaka, webflo, catch, piyuesh23, beejeebus: Optimize automatic cron subscriber by moving automatic cron to a module"

This reverts commit 6e0ce080.
parent 6e0ce080
...@@ -256,9 +256,6 @@ Action module ...@@ -256,9 +256,6 @@ Action module
Aggregator module Aggregator module
- Paris Liakos 'ParisLiakos' https://www.drupal.org/u/parisliakos - Paris Liakos 'ParisLiakos' https://www.drupal.org/u/parisliakos
Automated Cron module
- Daniel Wehner 'dawehner' https://www.drupal.org/u/dawehner
Ban module Ban module
- ? - ?
......
...@@ -41,7 +41,6 @@ ...@@ -41,7 +41,6 @@
"replace": { "replace": {
"drupal/action": "self.version", "drupal/action": "self.version",
"drupal/aggregator": "self.version", "drupal/aggregator": "self.version",
"drupal/automated_cron": "self.version",
"drupal/bartik": "self.version", "drupal/bartik": "self.version",
"drupal/ban": "self.version", "drupal/ban": "self.version",
"drupal/basic_auth": "self.version", "drupal/basic_auth": "self.version",
......
name: 'Automated Cron'
type: module
description: 'Provides an automated way to run cron jobs, by executing them at the end of a server response.'
package: Core
version: VERSION
core: 8.x
<?php
/**
* @file
* Provides an automated cron by executing it at the end of a response.
*/
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Form\FormStateInterface;
/**
* Implements hook_help().
*/
function automated_cron_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.automated_cron':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('The Automated Cron module runs cron operations for your site using normal browser/page requests instead of having to set up a separate cron job. The Automated Cron module checks at the end of each server response when cron operation was last ran and, if it has been too long since last run, it executes the cron tasks after sending a server response. For more information, see the <a href=":automated_cron-documentation">online documentation for the Automated Cron module</a>.', [':automated_cron-documentation' => 'https://www.drupal.org/documentation/modules/automated_cron']) . '</p>';
$output .= '<h3>' . t('Uses') . '</h3>';
$output .= '<dl>';
$output .= '<dt>' . t('Configuring Automated Cron') . '</dt>';
$output .= '<dd>' . t('On the <a href=":cron-settings">Cron page</a>, you can set the frequency (time interval) for running cron jobs.', [':cron-settings' => \Drupal::url('system.cron_settings')]) . '</dd>';
$output .= '<dt>' . t('Disabling Automated Cron') . '</dt>';
$output .= '<dd>' . t('To disable automated cron, the recommended method is to uninstall the module, to reduce site overhead. If you only want to disable it temporarily, you can set the frequency to Never on the Cron page, and then change the frequency back when you want to start it up again.') . '</dd>';
$output .= '</dl>';
return $output;
}
}
/**
* Implements hook_form_FORM_ID_alter() for the system_cron_settings() form.
*/
function automated_cron_form_system_cron_settings_alter(&$form, &$form_state) {
$automated_cron_settings = \Drupal::config('automated_cron.settings');
// Add automated cron settings.
$form['automated_cron'] = [
'#title' => t('Cron settings'),
'#type' => 'details',
'#open' => TRUE,
];
$options = [3600, 10800, 21600, 43200, 86400, 604800];
$form['automated_cron']['interval'] = [
'#type' => 'select',
'#title' => t('Run cron every'),
'#description' => t('More information about setting up scheduled tasks can be found by <a href="@url">reading the cron tutorial on drupal.org</a>.', ['@url' => 'https://www.drupal.org/cron']),
'#default_value' => $automated_cron_settings->get('interval'),
'#options' => [0 => t('Never')] + array_map([\Drupal::service('date.formatter'), 'formatInterval'], array_combine($options, $options)),
];
$form['actions']['#type'] = 'actions';
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => t('Save configuration'),
'#button_type' => 'primary',
];
// Add submit callback.
$form['#submit'][] = 'automated_cron_settings_submit';
// Theme this form as a config form.
$form['#theme'] = 'system_config_form';
}
/**
* Form submission handler for system_cron_settings().
*/
function automated_cron_settings_submit(array $form, FormStateInterface $form_state) {
\Drupal::configFactory()->getEditable('automated_cron.settings')
->set('interval', $form_state->getValue('interval'))
->save();
drupal_set_message(t('The configuration options have been saved.'));
}
services:
automated_cron.subscriber:
class: Drupal\automated_cron\EventSubscriber\AutomatedCron
arguments: ['@cron', '@config.factory', '@state']
tags:
- { name: event_subscriber }
# Schema for the configuration files of the Automated cron module.
automated_cron.settings:
type: config_object
label: 'Automated cron settings'
mapping:
interval:
type: integer
label: 'Run cron every'
...@@ -37,6 +37,7 @@ function testInstallProfileConfigOverwrite() { ...@@ -37,6 +37,7 @@ function testInstallProfileConfigOverwrite() {
// The expected configuration from the system module. // The expected configuration from the system module.
$expected_original_data = array( $expected_original_data = array(
'threshold' => array( 'threshold' => array(
'autorun' => 0,
'requirements_warning' => 172800, 'requirements_warning' => 172800,
'requirements_error' => 1209600, 'requirements_error' => 1209600,
), ),
...@@ -44,6 +45,7 @@ function testInstallProfileConfigOverwrite() { ...@@ -44,6 +45,7 @@ function testInstallProfileConfigOverwrite() {
// The expected active configuration altered by the install profile. // The expected active configuration altered by the install profile.
$expected_profile_data = array( $expected_profile_data = array(
'threshold' => array( 'threshold' => array(
'autorun' => 0,
'requirements_warning' => 259200, 'requirements_warning' => 259200,
'requirements_error' => 1209600, 'requirements_error' => 1209600,
), ),
......
threshold: threshold:
autorun: 0
requirements_warning: 172800 requirements_warning: 172800
requirements_error: 1209600 requirements_error: 1209600
...@@ -41,6 +41,9 @@ protected function setUp() { ...@@ -41,6 +41,9 @@ protected function setUp() {
$user = $this->drupalCreateUser(array('administer search', 'search content', 'use advanced search', 'access content', 'access site reports', 'administer site configuration')); $user = $this->drupalCreateUser(array('administer search', 'search content', 'use advanced search', 'access content', 'access site reports', 'administer site configuration'));
$this->drupalLogin($user); $this->drupalLogin($user);
// Make sure that auto-cron is disabled.
$this->config('system.cron')->set('threshold.autorun', 0)->save();
// Set up the search plugin. // Set up the search plugin.
$this->plugin = $this->container->get('plugin.manager.search')->createInstance('node_search'); $this->plugin = $this->container->get('plugin.manager.search')->createInstance('node_search');
......
threshold: threshold:
autorun: 0
requirements_warning: 172800 requirements_warning: 172800
requirements_error: 1209600 requirements_error: 1209600
...@@ -66,6 +66,9 @@ system.cron: ...@@ -66,6 +66,9 @@ system.cron:
type: mapping type: mapping
label: 'Thresholds' label: 'Thresholds'
mapping: mapping:
autorun:
type: integer
label: 'Run cron every'
requirements_warning: requirements_warning:
type: integer type: integer
label: 'Requirements warning period' label: 'Requirements warning period'
......
...@@ -2,10 +2,10 @@ ...@@ -2,10 +2,10 @@
/** /**
* @file * @file
* Contains \Drupal\automated_cron\EventSubscriber\AutomatedCron. * Contains \Drupal\system\EventSubscriber\AutomaticCron.
*/ */
namespace Drupal\automated_cron\EventSubscriber; namespace Drupal\system\EventSubscriber;
use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\CronInterface; use Drupal\Core\CronInterface;
...@@ -15,9 +15,9 @@ ...@@ -15,9 +15,9 @@
use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\KernelEvents;
/** /**
* A subscriber running cron after a response is sent. * A subscriber running cron when a request terminates.
*/ */
class AutomatedCron implements EventSubscriberInterface { class AutomaticCron implements EventSubscriberInterface {
/** /**
* The cron service. * The cron service.
...@@ -36,38 +36,43 @@ class AutomatedCron implements EventSubscriberInterface { ...@@ -36,38 +36,43 @@ class AutomatedCron implements EventSubscriberInterface {
/** /**
* The state key value store. * The state key value store.
* *
* @var \Drupal\Core\State\StateInterface; * Drupal\Core\State\StateInterface;
*/ */
protected $state; protected $state;
/** /**
* Constructs a new automated cron runner. * Construct a new automatic cron runner.
* *
* @param \Drupal\Core\CronInterface $cron * @param \Drupal\Core\CronInterface $cron
* The cron service. * The cron service.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory. * The config factory.
* @param \Drupal\Core\State\StateInterface $state * @param \Drupal\Core\State\StateInterface $state
* The state key-value store service. * The state key value store.
*/ */
public function __construct(CronInterface $cron, ConfigFactoryInterface $config_factory, StateInterface $state) { public function __construct(CronInterface $cron, ConfigFactoryInterface $config_factory, StateInterface $state) {
$this->cron = $cron; $this->cron = $cron;
$this->config = $config_factory->get('automated_cron.settings'); $this->config = $config_factory->get('system.cron');
$this->state = $state; $this->state = $state;
} }
/** /**
* Run the automated cron if enabled. * Run the automated cron if enabled.
* *
* @param \Symfony\Component\HttpKernel\Event\PostResponseEvent $event * @param Symfony\Component\HttpKernel\Event\PostResponseEvent $event
* The Event to process. * The Event to process.
*/ */
public function onTerminate(PostResponseEvent $event) { public function onTerminate(PostResponseEvent $event) {
$interval = $this->config->get('interval'); // If the site is not fully installed, suppress the automated cron run.
if ($interval > 0) { // Otherwise it could be triggered prematurely by Ajax requests during
$cron_next = $this->state->get('system.cron_last', 0) + $interval; // installation.
if ((int) $event->getRequest()->server->get('REQUEST_TIME') > $cron_next) { if ($this->state->get('install_task') == 'done') {
$this->cron->run(); $threshold = $this->config->get('threshold.autorun');
if ($threshold > 0) {
$cron_next = $this->state->get('system.cron_last', 0) + $threshold;
if (REQUEST_TIME > $cron_next) {
$this->cron->run();
}
} }
} }
} }
...@@ -79,7 +84,9 @@ public function onTerminate(PostResponseEvent $event) { ...@@ -79,7 +84,9 @@ public function onTerminate(PostResponseEvent $event) {
* An array of event listener definitions. * An array of event listener definitions.
*/ */
public static function getSubscribedEvents() { public static function getSubscribedEvents() {
return [KernelEvents::TERMINATE => [['onTerminate', 100]]]; $events[KernelEvents::TERMINATE][] = array('onTerminate', 100);
return $events;
} }
} }
...@@ -10,17 +10,16 @@ ...@@ -10,17 +10,16 @@
use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\CronInterface; use Drupal\Core\CronInterface;
use Drupal\Core\Datetime\DateFormatterInterface; use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\State\StateInterface; use Drupal\Core\State\StateInterface;
use Drupal\Core\Form\ConfigFormBase;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\RedirectResponse;
/** /**
* Configure cron settings for this site. * Configure cron settings for this site.
*/ */
class CronForm extends FormBase { class CronForm extends ConfigFormBase {
/** /**
* Stores the state storage service. * Stores the state storage service.
...@@ -43,13 +42,6 @@ class CronForm extends FormBase { ...@@ -43,13 +42,6 @@ class CronForm extends FormBase {
*/ */
protected $dateFormatter; protected $dateFormatter;
/**
* The module handler service.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface $moduleHandler
*/
protected $moduleHandler;
/** /**
* Constructs a CronForm object. * Constructs a CronForm object.
* *
...@@ -61,14 +53,12 @@ class CronForm extends FormBase { ...@@ -61,14 +53,12 @@ class CronForm extends FormBase {
* The cron service. * The cron service.
* @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter * @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
* The date formatter service. * The date formatter service.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler service.
*/ */
public function __construct(ConfigFactoryInterface $config_factory, StateInterface $state, CronInterface $cron, DateFormatterInterface $date_formatter, ModuleHandlerInterface $module_handler) { public function __construct(ConfigFactoryInterface $config_factory, StateInterface $state, CronInterface $cron, DateFormatterInterface $date_formatter) {
parent::__construct($config_factory);
$this->state = $state; $this->state = $state;
$this->cron = $cron; $this->cron = $cron;
$this->dateFormatter = $date_formatter; $this->dateFormatter = $date_formatter;
$this->moduleHandler = $module_handler;
} }
/** /**
...@@ -79,8 +69,7 @@ public static function create(ContainerInterface $container) { ...@@ -79,8 +69,7 @@ public static function create(ContainerInterface $container) {
$container->get('config.factory'), $container->get('config.factory'),
$container->get('state'), $container->get('state'),
$container->get('cron'), $container->get('cron'),
$container->get('date.formatter'), $container->get('date.formatter')
$container->get('module_handler')
); );
} }
...@@ -91,16 +80,26 @@ public function getFormId() { ...@@ -91,16 +80,26 @@ public function getFormId() {
return 'system_cron_settings'; return 'system_cron_settings';
} }
/**
* {@inheritdoc}
*/
protected function getEditableConfigNames() {
return ['system.cron'];
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function buildForm(array $form, FormStateInterface $form_state) { public function buildForm(array $form, FormStateInterface $form_state) {
$config = $this->config('system.cron');
$form['description'] = array( $form['description'] = array(
'#markup' => '<p>' . t('Cron takes care of running periodic tasks like checking for updates and indexing content for search.') . '</p>', '#markup' => '<p>' . t('Cron takes care of running periodic tasks like checking for updates and indexing content for search.') . '</p>',
); );
$form['run'] = array( $form['run'] = array(
'#type' => 'submit', '#type' => 'submit',
'#value' => t('Run cron'), '#value' => t('Run cron'),
'#submit' => array('::submitCron'),
); );
$status = '<p>' . $this->t('Last run: %time ago.', array('%time' => $this->dateFormatter->formatTimeDiffSince($this->state->get('system.cron_last')))) . '</p>'; $status = '<p>' . $this->t('Last run: %time ago.', array('%time' => $this->dateFormatter->formatTimeDiffSince($this->state->get('system.cron_last')))) . '</p>';
$form['status'] = array( $form['status'] = array(
...@@ -112,19 +111,38 @@ public function buildForm(array $form, FormStateInterface $form_state) { ...@@ -112,19 +111,38 @@ public function buildForm(array $form, FormStateInterface $form_state) {
'#markup' => '<p>' . t('To run cron from outside the site, go to <a href=":cron">@cron</a>', array(':cron' => $cron_url, '@cron' => $cron_url)) . '</p>', '#markup' => '<p>' . t('To run cron from outside the site, go to <a href=":cron">@cron</a>', array(':cron' => $cron_url, '@cron' => $cron_url)) . '</p>',
); );
if (!$this->moduleHandler->moduleExists('automated_cron')) { $form['cron'] = array(
$form['cron'] = array( '#title' => t('Cron settings'),
'#markup' => $this->t('Enable the <em>Automated Cron</em> module to allow cron execution at the end of a server response.'), '#type' => 'details',
); '#open' => TRUE,
} );
$options = array(3600, 10800, 21600, 43200, 86400, 604800);
$form['cron']['cron_safe_threshold'] = array(
'#type' => 'select',
'#title' => t('Run cron every'),
'#description' => t('More information about setting up scheduled tasks can be found by <a href=":url">reading the cron tutorial on drupal.org</a>.', array(':url' => 'https://www.drupal.org/cron')),
'#default_value' => $config->get('threshold.autorun'),
'#options' => array(0 => t('Never')) + array_map(array($this->dateFormatter, 'formatInterval'), array_combine($options, $options)),
);
return $form; return parent::buildForm($form, $form_state);
} }
/** /**
* Runs cron and reloads the page. * {@inheritdoc}
*/ */
public function submitForm(array &$form, FormStateInterface $form_state) { public function submitForm(array &$form, FormStateInterface $form_state) {
$this->config('system.cron')
->set('threshold.autorun', $form_state->getValue('cron_safe_threshold'))
->save();
parent::submitForm($form, $form_state);
}
/**
* Runs cron and reloads the page.
*/
public function submitCron(array &$form, FormStateInterface $form_state) {
// Run cron manually from Cron form. // Run cron manually from Cron form.
if ($this->cron->run()) { if ($this->cron->run()) {
drupal_set_message(t('Cron run successfully.')); drupal_set_message(t('Cron run successfully.'));
......
...@@ -21,7 +21,7 @@ class CronRunTest extends WebTestBase { ...@@ -21,7 +21,7 @@ class CronRunTest extends WebTestBase {
* *
* @var array * @var array
*/ */
public static $modules = ['common_test', 'common_test_cron_helper', 'automated_cron']; public static $modules = array('common_test', 'common_test_cron_helper');
/** /**
* Test cron runs. * Test cron runs.
...@@ -43,42 +43,42 @@ function testCronRun() { ...@@ -43,42 +43,42 @@ function testCronRun() {
} }
/** /**
* Ensure that the automated cron run module is working. * Ensure that the automatic cron run feature is working.
* *
* In these tests we do not use REQUEST_TIME to track start time, because we * In these tests we do not use REQUEST_TIME to track start time, because we
* need the exact time when cron is triggered. * need the exact time when cron is triggered.
*/ */
function testAutomatedCron() { function testAutomaticCron() {
// Test with a logged in user; anonymous users likely don't cause Drupal to // Test with a logged in user; anonymous users likely don't cause Drupal to
// fully bootstrap, because of the internal page cache or an external // fully bootstrap, because of the internal page cache or an external
// reverse proxy. Reuse this user for disabling cron later in the test. // reverse proxy. Reuse this user for disabling cron later in the test.
$admin_user = $this->drupalCreateUser(array('administer site configuration')); $admin_user = $this->drupalCreateUser(array('administer site configuration'));
$this->drupalLogin($admin_user); $this->drupalLogin($admin_user);
// Ensure cron does not run when a non-zero cron interval is specified and // Ensure cron does not run when the cron threshold is enabled and was
// was not passed. // not passed.
$cron_last = time(); $cron_last = time();
$cron_safe_interval = 100; $cron_safe_threshold = 100;
\Drupal::state()->set('system.cron_last', $cron_last); \Drupal::state()->set('system.cron_last', $cron_last);
$this->config('automated_cron.settings') $this->config('system.cron')
->set('interval', $cron_safe_interval) ->set('threshold.autorun', $cron_safe_threshold)
->save(); ->save();
$this->drupalGet(''); $this->drupalGet('');
$this->assertTrue($cron_last == \Drupal::state()->get('system.cron_last'), 'Cron does not run when the cron interval is not passed.'); $this->assertTrue($cron_last == \Drupal::state()->get('system.cron_last'), 'Cron does not run when the cron threshold is not passed.');
// Test if cron runs when the cron interval was passed. // Test if cron runs when the cron threshold was passed.
$cron_last = time() - 200; $cron_last = time() - 200;
\Drupal::state()->set('system.cron_last', $cron_last); \Drupal::state()->set('system.cron_last', $cron_last);
$this->drupalGet(''); $this->drupalGet('');
sleep(1); sleep(1);
$this->assertTrue($cron_last < \Drupal::state()->get('system.cron_last'), 'Cron runs when the cron interval is passed.'); $this->assertTrue($cron_last < \Drupal::state()->get('system.cron_last'), 'Cron runs when the cron threshold is passed.');
// Disable cron through the interface by setting the interval to zero. // Disable the cron threshold through the interface.
$this->drupalPostForm('admin/config/system/cron', ['interval' => 0], t('Save configuration')); $this->drupalPostForm('admin/config/system/cron', array('cron_safe_threshold' => 0), t('Save configuration'));
$this->assertText(t('The configuration options have been saved.')); $this->assertText(t('The configuration options have been saved.'));
$this->drupalLogout(); $this->drupalLogout();
// Test if cron does not run when the cron interval is set to zero. // Test if cron does not run when the cron threshold is disabled.
$cron_last = time() - 200; $cron_last = time() - 200;
\Drupal::state()->set('system.cron_last', $cron_last); \Drupal::state()->set('system.cron_last', $cron_last);
$this->drupalGet(''); $this->drupalGet('');
......
<?php
/**
* @file
* Contains \Drupal\system\Tests\Update\AutomatedCronUpdateWithAutomatedCronTest.
*/
namespace Drupal\system\Tests\Update;
/**
* Ensures that the automated cron module is installed on update.
*
* @group Update
*/
class AutomatedCronUpdateWithAutomatedCronTest extends UpdatePathTestBase {
/**
* {@inheritdoc}
*/
protected function setDatabaseDumpFiles() {
$this->databaseDumpFiles = [
__DIR__ . '/../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
];
}
/**
* Ensures that automated cron module isn installed and the config migrated.
*/
public function testUpdate() {
$this->runUpdates();
$module_data = \Drupal::config('core.extension')->get('module');
$this->assertTrue(isset($module_data['automated_cron']), 'The automated cron module was installed.');
}
}
<?php
/**
* @file
* Contains \Drupal\system\Tests\Update\AutomatedCronUpdateWithoutAutomatedCronTest.
*/
namespace Drupal\system\Tests\Update;
/**
* Ensures that the automated cron module is not installed on update.
*
* @group Update
*/
class AutomatedCronUpdateWithoutAutomatedCronTest extends UpdatePathTestBase {
/**
* {@inheritdoc}
*/
protected function setDatabaseDumpFiles() {
$this->databaseDumpFiles = [
__DIR__ . '/../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
__DIR__ . '/../../../tests/fixtures/update/drupal-8.without_automated_cron.php',
];
}
/**
* Ensures that automated cron module isn't installed and the config migrated.
*/
public function testUpdate() {
$this->runUpdates();
$module_data = \Drupal::config('core.extension')->get('module');
$this->assertFalse(isset($module_data['automated_cron']), 'The automated cron module was not installed.');
}
}
...@@ -263,7 +263,6 @@ protected function runUpdates() { ...@@ -263,7 +263,6 @@ protected function runUpdates() {
$names = $this->container->get('config.storage')->listAll(); $names = $this->container->get('config.storage')->listAll();
/** @var \Drupal\Core\Config\TypedConfigManagerInterface $typed_config */ /** @var \Drupal\Core\Config\TypedConfigManagerInterface $typed_config */
$typed_config = $this->container->get('config.typed'); $typed_config = $this->container->get('config.typed');
$typed_config->clearCachedDefinitions();
foreach ($names as $name) { foreach ($names as $name) {
$config = $this->config($name); $config = $this->config($name);