Break all the crons
Categories
Component ID
Component name
Component type
Maintenance status
Development status
Component security advisory coverage
Component created
Component changed
Component body
An example module to practice recovering from a fatal error created during cron jobs. It creates an artificial fatal error then prints a debug backtrace on the cron page to help identify the problem and work on a solution.
Requires Bad judgement.
One possible way to manage cron for Drupal is using Jenkins. A reason for centralizing cron jobs with the Java bloat of Jenkins is to get alerts when cron jobs fail or servers are unavailable.
When Drupal 7 crons fail, they don't output any failure message. The best you can hope for appears to be errors saved to the database log. Lots of people don't review their logs regularly; some don't even keep the database logging module enabled.
Even if you enable error reporting in Logging and errors to display all messages, it still won't show fatal error information on the cron page.
The handling of fatal errors during Drupal crons isn't an accident, either. As reference, this is the code that executes all the hook_cron()
implementations in includes/common.inc:drupal_cron_run()
.
foreach (module_implements('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);
}
}
The watchdog_exception
function is a wrapper for watchdog
. Since Drupal allows developers the ability to extend watchdog()
with hook_watchdog()
, we can opt-in to error messages for the cron.php
script.
This module shows an example of exactly that. It throws a PHP error, then prints the backtrace so you can have a clue that something broke and how to fix it.
#0 break_all_the_crons_watchdog(Array ([type] => php,[message] => %type: !message in %function (line %line of %file).,[variables] => Array ([%type] => User error,[!message] => All the crons are broken,[%function] => break_all_the_crons_cron(),[%file] => /var/phpdev/sites/all/modules/break_all_the_crons/break_all_the_crons.module,[%line] => 12,[severity_level] => 3),[severity] => 3,[link] => ,[user] => stdClass Object ([uid] => 0,[hostname] => 192.30.60.10,[roles] => Array ([1] => anonymous user),[cache] => 0),[uid] => 0,[request_uri] => https://phpdev.net/cron.php?cron_key=qCxPSVxiN6sNcqm6y1sfCbXIiKoVyLUUlLMahIPs1OE,[referer] => https://phpdev.net/admin/reports/event/125,[ip] => 192.30.60.10,[timestamp] => 1417198015))
#1 call_user_func_array(break_all_the_crons_watchdog, Array ([2] => Array ([type] => php,[message] => %type: !message in %function (line %line of %file).,[variables] => Array ([%type] => User error,[!message] => All the crons are broken,[%function] => break_all_the_crons_cron(),[%file] => /var/phpdev/sites/all/modules/break_all_the_crons/break_all_the_crons.module,[%line] => 12,[severity_level] => 3),[severity] => 3,[link] => ,[user] => stdClass Object ([uid] => 0,[hostname] => 192.30.60.10,[roles] => Array ([1] => anonymous user),[cache] => 0),[uid] => 0,[request_uri] => https://phpdev.net/cron.php?cron_key=qCxPSVxiN6sNcqm6y1sfCbXIiKoVyLUUlLMahIPs1OE,[referer] => https://phpdev.net/admin/reports/event/125,[ip] => 192.30.60.10,[timestamp] => 1417198015))) called at [/var/phpdev/includes/module.inc:866]
#2 module_invoke(break_all_the_crons, watchdog, Array ([type] => php,[message] => %type: !message in %function (line %line of %file).,[variables] => Array ([%type] => User error,[!message] => All the crons are broken,[%function] => break_all_the_crons_cron(),[%file] => /var/phpdev/sites/all/modules/break_all_the_crons/break_all_the_crons.module,[%line] => 12,[severity_level] => 3),[severity] => 3,[link] => ,[user] => stdClass Object ([uid] => 0,[hostname] => 192.30.60.10,[roles] => Array ([1] => anonymous user),[cache] => 0),[uid] => 0,[request_uri] => https://phpdev.net/cron.php?cron_key=qCxPSVxiN6sNcqm6y1sfCbXIiKoVyLUUlLMahIPs1OE,[referer] => https://phpdev.net/admin/reports/event/125,[ip] => 192.30.60.10,[timestamp] => 1417198015)) called at [/var/phpdev/includes/bootstrap.inc:1752]
#3 watchdog(php, %type: !message in %function (line %line of %file)., Array ([%type] => User error,[!message] => All the crons are broken,[%function] => break_all_the_crons_cron(),[%file] => /var/phpdev/sites/all/modules/break_all_the_crons/break_all_the_crons.module,[%line] => 12,[severity_level] => 3), 3) called at [/var/phpdev/includes/errors.inc:202]
#4 _drupal_log_error(Array ([%type] => User error,[!message] => All the crons are broken,[%function] => break_all_the_crons_cron(),[%file] => /var/phpdev/sites/all/modules/break_all_the_crons/break_all_the_crons.module,[%line] => 12,[severity_level] => 3), ) called at [/var/phpdev/includes/errors.inc:75]
#5 _drupal_error_handler_real(256, All the crons are broken, /var/phpdev/sites/all/modules/break_all_the_crons/break_all_the_crons.module, 12, Array ()) called at [/var/phpdev/includes/bootstrap.inc:2331]
#6 _drupal_error_handler(256, All the crons are broken, /var/phpdev/sites/all/modules/break_all_the_crons/break_all_the_crons.module, 12, Array ())
#7 trigger_error(All the crons are broken, 256) called at [/var/phpdev/sites/all/modules/break_all_the_crons/break_all_the_crons.module:12]
#8 break_all_the_crons_cron()
#9 call_user_func_array(break_all_the_crons_cron, Array ()) called at [/var/phpdev/includes/module.inc:866]
#10 module_invoke(break_all_the_crons, cron) called at [/var/phpdev/includes/common.inc:5299]
#11 drupal_cron_run() called at [/var/phpdev/cron.php:25]
The backtrace in this example prints debug backtraces for the following error codes:
WATCHDOG_EMERGENCY: Emergency, system is unusable.
WATCHDOG_ALERT: Alert, action must be taken immediately.
WATCHDOG_CRITICAL: Critical conditions.
WATCHDOG_ERROR: Error conditions.
The if statement will suppress the backtrace for the following:
WATCHDOG_WARNING: Warning conditions.
WATCHDOG_NOTICE: Normal but significant conditions.
WATCHDOG_INFO: Informational messages.
WATCHDOG_DEBUG: Debug-level messages.
This looks for cron.php
in the path because if drush cron
is the standard method of running crons, it already supports printing the error to stdout:
root@localhost:/var/www# drush cron
All the crons are broken break_all_the_crons.module:12 [error]
Cron run successful. [success]
root@localhost:/var/www#