ultimate_cron.admin.inc 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  1. <?php
  2. /**
  3. * @file
  4. */
  5. /**
  6. * Menu callback: runs cron and returns to status-report page.
  7. */
  8. function ultimate_cron_run_cron() {
  9. // Run the cron and return
  10. ultimate_cron_cron_run(TRUE);
  11. drupal_goto('admin/reports/status');
  12. }
  13. /**
  14. * Settings form.
  15. */
  16. function ultimate_cron_settings_form() {
  17. $form = array();
  18. $advanced_help_enabled = module_exists('advanced_help');
  19. // General settings -----------------------------------
  20. $form['general'] = array(
  21. '#title' => t('General'),
  22. '#type' => 'fieldset',
  23. '#collapsible' => TRUE,
  24. '#collapsed' => FALSE,
  25. '#tree' => FALSE,
  26. );
  27. $form['general']['ultimate_cron_handle_prefix'] = array(
  28. '#title' => t("Handle prefix"),
  29. '#type' => 'textfield',
  30. '#default_value' => variable_get('ultimate_cron_handle_prefix', ULTIMATE_CRON_HANDLE_PREFIX),
  31. '#description' => ($advanced_help_enabled ? theme('advanced_help_topic', array(
  32. 'module' => 'ultimate_cron',
  33. 'topic' => 'handle_prefix',
  34. 'type' => 'icon')
  35. ) : '') . t('Handle prefix. Use with care. Changing this from the default value ("' . ULTIMATE_CRON_HANDLE_PREFIX . '"), might break compatibility with 3rd party modules. Also, make sure that no jobs are running when changing this.'),
  36. );
  37. $form['general']['ultimate_cron_simultaneous_connections'] = array(
  38. '#title' => t("Simultaneous connections"),
  39. '#type' => 'textfield',
  40. '#default_value' => variable_get('ultimate_cron_simultaneous_connections', ULTIMATE_CRON_SIMULTANEOUS_CONNECTIONS),
  41. '#description' => ($advanced_help_enabled ? theme('advanced_help_topic', array(
  42. 'module' => 'ultimate_cron',
  43. 'topic' => 'simultaneous_connections',
  44. 'type' => 'icon')
  45. ) : '') . t('Maximum number of simultaneous connections'),
  46. );
  47. $form['general']['ultimate_cron_rule'] = array(
  48. '#title' => t("Default rule"),
  49. '#type' => 'textfield',
  50. '#default_value' => variable_get('ultimate_cron_rule', ULTIMATE_CRON_RULE),
  51. '#description' => ($advanced_help_enabled ? theme('advanced_help_topic', array(
  52. 'module' => 'ultimate_cron',
  53. 'topic' => 'rules',
  54. 'type' => 'icon')
  55. ) : '') . t('Enter the default fallback rule'),
  56. );
  57. $form['general']['ultimate_cron_cleanup_log'] = array(
  58. '#title' => t("Clean up logs older than X seconds"),
  59. '#type' => 'textfield',
  60. '#default_value' => variable_get('ultimate_cron_cleanup_log', ULTIMATE_CRON_CLEANUP_LOG),
  61. '#description' => ($advanced_help_enabled ? theme('advanced_help_topic', array(
  62. 'module' => 'ultimate_cron',
  63. 'topic' => 'cleanup_log',
  64. 'type' => 'icon')
  65. ) : '') . t('Enter maximum age, in seconds, for log entries'),
  66. );
  67. $form['general']['ultimate_cron_catch_up'] = array(
  68. '#title' => t('Default catch up'),
  69. '#type' => 'textfield',
  70. '#default_value' => variable_get('ultimate_cron_catch_up', ULTIMATE_CRON_CATCH_UP),
  71. '#description' => ($advanced_help_enabled ? theme('advanced_help_topic', array(
  72. 'module' => 'ultimate_cron',
  73. 'topic' => 'catch_up',
  74. 'type' => 'icon')
  75. ) : '') . t('Time in seconds to catch up, if a job could not be run within its time frame. (blank = ' . variable_get('ultimate_cron_catch_up', ULTIMATE_CRON_CATCH_UP) . ')'),
  76. );
  77. $form['general']['ultimate_cron_queue_polling_latency'] = array(
  78. '#title' => t("Queue polling latency"),
  79. '#type' => 'textfield',
  80. '#default_value' => variable_get('ultimate_cron_queue_polling_latency', ULTIMATE_CRON_QUEUE_POLLING_LATENCY),
  81. '#description' => ($advanced_help_enabled ? theme('advanced_help_topic', array(
  82. 'module' => 'ultimate_cron',
  83. 'topic' => 'polling_latency',
  84. 'type' => 'icon')
  85. ) : '') . t('Queue polling latency in miliseconds. Leave blank to disable continuous processing of queues.'),
  86. );
  87. $form['general']['ultimate_cron_queue_lease_time'] = array(
  88. '#title' => t('Queue lease time'),
  89. '#type' => 'textfield',
  90. '#default_value' => variable_get('ultimate_cron_queue_lease_time', ULTIMATE_CRON_QUEUE_LEASE_TIME),
  91. '#description' => ($advanced_help_enabled ? theme('advanced_help_topic', array(
  92. 'module' => 'ultimate_cron',
  93. 'topic' => 'queue_lease_time',
  94. 'type' => 'icon')
  95. ) : '') . t('Time in seconds to keep lock on claimed item'),
  96. );
  97. $methods = module_invoke_all('service_group');
  98. $options = ultimate_cron_get_service_groups();
  99. foreach ($options as $key => &$value) {
  100. $value = (empty($value['description']) ? $key : $value['description']) . ' (' . join(',', $value['hosts']) . ') : ' . $methods['methods'][$value['method']];
  101. }
  102. $form['general']['ultimate_cron_service_group'] = array(
  103. '#type' => 'select',
  104. '#title' => t('Service group'),
  105. '#description' => ($advanced_help_enabled ? theme('advanced_help_topic', array(
  106. 'module' => 'ultimate_cron',
  107. 'topic' => 'service_group',
  108. 'type' => 'icon')
  109. ) : '') . t('Service group to use for all jobs. See Background Process !url for managing service groups.', array('!url' => l(t('settings'), 'admin/config/system/background-process'))),
  110. '#options' => $options,
  111. '#default_value' => variable_get('ultimate_cron_service_group', ULTIMATE_CRON_SERVICE_GROUP),
  112. );
  113. $form['general']['ultimate_cron_poorman'] = array(
  114. '#title' => t("Poormans cron"),
  115. '#type' => 'checkbox',
  116. '#default_value' => variable_get('ultimate_cron_poorman', ULTIMATE_CRON_POORMAN),
  117. '#description' => ($advanced_help_enabled ? theme('advanced_help_topic', array(
  118. 'module' => 'ultimate_cron',
  119. 'topic' => 'poorman',
  120. 'type' => 'icon')
  121. ) : '') . t('Keep background process alive, checking for cron every minute.'),
  122. );
  123. $form = system_settings_form($form);
  124. return $form;
  125. }
  126. /**
  127. * Function settings form.
  128. */
  129. function ultimate_cron_function_settings_form($form, &$form_state, $function) {
  130. $hooks = ultimate_cron_get_hooks();
  131. if (!isset($hooks[(string)$function])) {
  132. drupal_not_found();
  133. exit;
  134. }
  135. // Load settings
  136. $hook = $hooks[$function];
  137. $conf = ultimate_cron_get_settings($function);
  138. $conf += _ultimate_cron_default_settings();
  139. // Setup form
  140. drupal_set_title(check_plain($function));
  141. $form = array();
  142. $advanced_help_enabled = module_exists('advanced_help');
  143. // General settings -----------------------------------
  144. $form['function'] = array(
  145. '#type' => 'value',
  146. '#value' => $function,
  147. );
  148. $form['general'] = array(
  149. '#title' => t('General'),
  150. '#type' => 'fieldset',
  151. '#collapsible' => TRUE,
  152. '#collapsed' => FALSE,
  153. '#tree' => TRUE,
  154. );
  155. $form['general']['enabled'] = array(
  156. '#title' => t('Enabled'),
  157. '#type' => 'checkbox',
  158. '#default_value' => $conf['enabled'],
  159. '#description' => t('Enable this cron job.'),
  160. );
  161. $form['general']['rules'] = array(
  162. '#title' => t('Rules'),
  163. '#type' => 'textfield',
  164. '#default_value' => implode(';', $conf['rules']),
  165. '#description' => ($advanced_help_enabled ? theme('advanced_help_topic', array(
  166. 'module' => 'ultimate_cron',
  167. 'topic' => 'rules',
  168. 'type' => 'icon')
  169. ) : '') . t('Semi-colon separated list of rules for this job. (blank = ' . implode(';', $hook['settings']['rules']) . ')'),
  170. );
  171. $form['general']['catch_up'] = array(
  172. '#title' => t('Catch up'),
  173. '#type' => 'textfield',
  174. '#default_value' => $conf['catch_up'],
  175. '#description' => ($advanced_help_enabled ? theme('advanced_help_topic', array(
  176. 'module' => 'ultimate_cron',
  177. 'topic' => 'catch_up',
  178. 'type' => 'icon')
  179. ) : '') . t('Time in seconds to catch up, if a job could not be run within its time frame. (blank = ' . variable_get('ultimate_cron_catch_up', ULTIMATE_CRON_CATCH_UP) . ')'),
  180. );
  181. if (strpos($function, 'ultimate_cron_queue_') === 0) {
  182. $form['general']['queue_lease_time'] = array(
  183. '#title' => t('Queue lease time'),
  184. '#type' => 'textfield',
  185. '#default_value' => $conf['queue_lease_time'],
  186. '#description' => ($advanced_help_enabled ? theme('advanced_help_topic', array(
  187. 'module' => 'ultimate_cron',
  188. 'topic' => 'queue_lease_time',
  189. 'type' => 'icon')
  190. ) : '') . t('Time in seconds to keep lock on claimed item. (blank = ' . variable_get('ultimate_cron_queue_lease_time', ULTIMATE_CRON_QUEUE_LEASE_TIME) . ')'),
  191. );
  192. }
  193. $methods = module_invoke_all('service_group');
  194. $service_groups = $options = ultimate_cron_get_service_groups();
  195. foreach ($options as $key => &$value) {
  196. $value = (empty($value['description']) ? $key : $value['description']) . ' (' . join(',', $value['hosts']) . ') : ' . $methods['methods'][$value['method']];
  197. }
  198. $options += array(
  199. NULL => 'Ultimate Cron service group (' . join(',', $service_groups[variable_get('ultimate_cron_service_group', ULTIMATE_CRON_SERVICE_GROUP)]['hosts']) . ') : ' . $methods['methods'][$service_groups[variable_get('ultimate_cron_service_group', ULTIMATE_CRON_SERVICE_GROUP)]['method']]
  200. );
  201. $form['general']['service_group'] = array(
  202. '#type' => 'select',
  203. '#title' => t('Service group'),
  204. '#description' => ($advanced_help_enabled ? theme('advanced_help_topic', array(
  205. 'module' => 'ultimate_cron',
  206. 'topic' => 'service_group',
  207. 'type' => 'icon')
  208. ) : '') . t('Service group to use for this job. See Background Process !url for managing service groups.', array('!url' => l(t('settings'), 'admin/config/system/background-process'))),
  209. '#options' => $options,
  210. '#default_value' => isset($conf['service_group']) ? $conf['service_group'] : NULL,
  211. );
  212. $form['buttons'] = array(
  213. '#weight' => 1000,
  214. );
  215. $form['buttons']['submit'] = array(
  216. '#type' => 'submit',
  217. '#value' => t('Save settings'),
  218. );
  219. $form['#redirect'] = 'admin/config/system/cron';
  220. return $form;
  221. }
  222. /**
  223. * Validate handler for function settings.
  224. */
  225. function ultimate_cron_function_settings_form_validate($form, &$form_state) {
  226. $conf =& $form_state['values']['general'];
  227. $conf['rules'] = trim($conf['rules']);
  228. $conf['rules'] = $conf['rules'] ? explode(';', $conf['rules']) : array();
  229. if ($conf['rules']) {
  230. foreach ($conf['rules'] as &$rule) {
  231. $rule = trim($rule);
  232. if (!ultimate_cron_validate_rule($rule)) {
  233. form_set_error('rules', t('Invalid rule.'));
  234. }
  235. }
  236. }
  237. else {
  238. unset($conf['rules']);
  239. }
  240. }
  241. /**
  242. * Submit handler for function settings.
  243. */
  244. function ultimate_cron_function_settings_form_submit($form, &$form_state) {
  245. $conf =& $form_state['values']['general'];
  246. ultimate_cron_set_settings($form_state['values']['function'], $conf);
  247. unset($form_state['storage']);
  248. }
  249. /**
  250. * Page overviewing cron jobs.
  251. */
  252. function ultimate_cron_view_page($status = NULL) {
  253. require_once 'CronRule.class.php';
  254. drupal_add_css(drupal_get_path('module', 'ultimate_cron') . '/css/ultimate_cron.admin.css');
  255. drupal_add_js(drupal_get_path('module', 'ultimate_cron') . '/js/ultimate_cron.js');
  256. if (module_exists('nodejs')) {
  257. drupal_add_js(array(
  258. 'ultimate_cron' => array(
  259. 'processes' => new stdClass(),
  260. 'skew' => 0,
  261. 'handle_prefix' => variable_get('ultimate_cron_handle_prefix', ULTIMATE_CRON_HANDLE_PREFIX),
  262. ),
  263. ), 'setting');
  264. nodejs_send_content_channel_token('ultimate_cron');
  265. nodejs_send_content_channel_token('background_process');
  266. nodejs_send_content_channel_token('progress');
  267. drupal_add_js(drupal_get_path('module', 'ultimate_cron') . '/js/nodejs.ultimate_cron.js');
  268. }
  269. module_load_install('ultimate_cron');
  270. $requirements = ultimate_cron_requirements('runtime');
  271. if ($requirements['ultimate_cron']['severity'] != REQUIREMENT_OK) {
  272. drupal_set_message($requirements['ultimate_cron']['value'], 'error');
  273. drupal_set_message($requirements['ultimate_cron']['description'], 'error');
  274. }
  275. // Get hooks and their data
  276. $data = _ultimate_cron_preload_cron_data();
  277. $hooks = ultimate_cron_get_hooks();
  278. $modules = array();
  279. foreach ($hooks as $function => $hook) {
  280. $hook['settings'] = $data[$function]['settings'] + $hook['settings'];
  281. $hook['background_process'] = $data[$function]['background_process'];
  282. $hook['log'] = ultimate_cron_get_log($function);
  283. $modules[$hook['module']][$function] = $hook;
  284. }
  285. $headers = array('', t('Module'), t('Function'), t('Rules'), t('Start'), t('Duration'), t('Status'), array('colspan' => 3, 'data' => ''), l(t('Run all'), 'admin/reports/status/run-cron', array('query' => drupal_get_destination())));
  286. $output = '';
  287. $rows = array();
  288. $handle_prefix = variable_get('ultimate_cron_handle_prefix', ULTIMATE_CRON_HANDLE_PREFIX);
  289. $overview = array();
  290. $overview['running'] = 0;
  291. $overview['success'] = 0;
  292. $overview['info'] = 0;
  293. $overview['warning'] = 0;
  294. $overview['error'] = 0;
  295. // Used for JS encodeURIComponent emulation
  296. $revert = array('%21'=>'!', '%2A'=>'*', '%27'=>"'", '%28'=>'(', '%29'=>')');
  297. foreach ($modules as $module => $hooks) {
  298. foreach ($hooks as $function => $hook) {
  299. // Setup settings
  300. $conf = $hook['settings'];
  301. $rules = $hook['settings']['rules'];
  302. $cron = new CronRule();
  303. $parsed_rules = array();
  304. foreach ($rules as $rule) {
  305. $cron->rule = $rule;
  306. $cron->offset = $hook['delta'];
  307. $parsed_rules[] = $cron->parseRule();
  308. }
  309. // Setup process
  310. $process = $hook['background_process'];
  311. $service_host = empty($process->service_host) ? t('N/A') : $process->service_host;
  312. // Setup log
  313. $log = $hook['log'];
  314. if (!$log) {
  315. $log = array(
  316. 'severity' => -1,
  317. 'status' => NULL,
  318. 'start' => NULL,
  319. 'end' => NULL,
  320. );
  321. }
  322. $severity_type = $log['severity'] < 0 ? 'success' : ($log['severity'] >= WATCHDOG_NOTICE ? 'info' : ($log['severity'] >= WATCHDOG_WARNING ? 'warning' : 'error'));
  323. $css_status = !empty($process) ? 'running' : $severity_type;
  324. $short_msg = $log['severity'];
  325. $msg = !empty($log['msg']) ? $log['msg'] : t('No errors');
  326. $duration = '';
  327. if ($process) {
  328. $overview['running']++;
  329. $log['previous_start'] = $log['start'];
  330. $log['previous_end'] = $log['end'];
  331. $log['start'] = $process->start;
  332. if ($process->status == BACKGROUND_PROCESS_STATUS_RUNNING) {
  333. $log['end'] = microtime(TRUE);
  334. }
  335. else {
  336. $log['end'] = NULL;
  337. }
  338. $progress = progress_get_progress($handle_prefix . $function);
  339. if ($progress && $progress->progress > 0) {
  340. $duration .= sprintf(" (%d%%)", $progress->progress * 100);
  341. }
  342. }
  343. $overview[$severity_type]++;
  344. $link_configure = '';
  345. if (!empty($hook['configure'])) {
  346. $link_configure = _ultimate_cron_l('Settings', $hook['configure']);
  347. }
  348. $link_unlock = '';
  349. if ($process) {
  350. $link_unlock = _ultimate_cron_l('Unlock', 'background-process/unlock/' . $process->handle);
  351. }
  352. $link_settings = _ultimate_cron_l('Schedule', 'admin/config/system/cron/settings/' . $function);
  353. $link_execute = _ultimate_cron_l('Run', 'admin/ultimate-cron/service/start/' . $function);
  354. $link_log = _ultimate_cron_l('Log', 'admin/reports/cron/' . $function);
  355. $enable = !empty($conf) && empty($conf['enabled']);
  356. $link_toggle = _ultimate_cron_l($enable ? 'Enable' : 'Disable', 'admin/ultimate-cron/service/' . ($enable ? 'enable' : 'disable') . '/' . $function);
  357. $data = array(
  358. array('class' => $enable ? 'ultimate-cron-admin-enable' : 'ultimate-cron-admin-disable'),
  359. array('class' => 'ultimate-cron-admin-module'),
  360. array('class' => 'ultimate-cron-admin-function'),
  361. array('class' => 'ultimate-cron-admin-rules'),
  362. array('class' => 'ultimate-cron-admin-start'),
  363. array('class' => 'ultimate-cron-admin-end'),
  364. array('class' => 'ultimate-cron-admin-status ultimate-cron-admin-status-' . $css_status),
  365. array('class' => 'ultimate-cron-admin-settings'),
  366. array('class' => 'ultimate-cron-admin-configure'),
  367. array('class' => 'ultimate-cron-admin-log'),
  368. array('class' => $process ? 'ultimate-cron-admin-unlock' : 'ultimate-cron-admin-execute'),
  369. );
  370. $data[0]['data'] = $link_toggle;
  371. $data[0]['title'] = $enable ? t('Enable') : t('Disable');
  372. $data[1]['data'] = ultimate_cron_module_name($module);
  373. $data[2]['data'] = $hook['description'];
  374. $data[2]['title'] = $function;
  375. $data[3]['data'] = join("<br/>", $rules);
  376. $data[3]['title'] = join("\n", $parsed_rules);
  377. $data[4]['data'] = $log['start'] ? format_date((int)$log['start'], 'custom', 'Y-m-d H:i:s') : t('Never');
  378. $data[5]['data'] = $log['end'] ? gmdate('H:i:s', (int)($log['end'] - $log['start'])) . $duration : ($process ? t('Starting') : t('N/A'));
  379. $finish = !empty($log['previous_end']) ? $log['previous_end'] : $log['end'];
  380. $data[5]['title'] = t('Previous run finished @ !timestamp', array(
  381. '!timestamp' => $finish ? format_date((int)$finish, 'custom', 'Y-m-d H:i:s') : t('N/A')
  382. ));
  383. if (!empty($log['previous_start'])) {
  384. $data[4]['title'] = t('Previous run started @ !timestamp', array(
  385. '!timestamp' => format_date((int)$log['previous_start'], 'custom', 'Y-m-d H:i:s'),
  386. ));
  387. $data[5]['title'] .= ' - ' . t('Run time: !duration', array(
  388. '!duration' => gmdate('H:i:s', (int)($log['previous_end'] - $log['previous_start'])) . $duration,
  389. ));
  390. }
  391. if ($process) {
  392. $data[6]['data'] = '<span>' . t('Running') . '</span>';
  393. $data[6]['title'] = t('Running on @host', array('@host' => $service_host));
  394. }
  395. else {
  396. $data[6]['data'] = '<span>' . $short_msg . '</span>';
  397. $data[6]['title'] = strip_tags(html_entity_decode($msg, ENT_QUOTES));
  398. }
  399. $data[7]['data'] = $link_settings;
  400. $data[7]['title'] = t('Schedule');
  401. $data[8]['data'] = $link_configure;
  402. $data[8]['title'] = $link_configure ? t('Settings') : '';
  403. $data[9]['data'] = $link_log;
  404. $data[9]['title'] = t('Log');
  405. $data[10]['data'] = ($process ? $link_unlock : $link_execute);
  406. $data[10]['title'] = ($process ? t('Unlock') : t('Run'));
  407. $rows[(int)$enable][] = array(
  408. 'class' => array('row-' . str_replace('%', '_', strtr(rawurlencode($function), $revert))),
  409. 'data' => $data,
  410. 'style' => ($status && $status != 'all' && ($css_status != $status) ? 'display: none' : ''),
  411. );
  412. }
  413. }
  414. if (!empty($rows[0])) {
  415. $output .= theme('table', array(
  416. 'header' => $headers,
  417. 'rows' => $rows[0],
  418. 'attributes' => array('id' => array('ultimate-cron-view'))
  419. ));
  420. $output .= '<div class="clear-block"></div>';
  421. }
  422. if (!empty($rows[1])) {
  423. $headers = array('', t('Module'), t('Function'), t('Rules'), t('Start'), t('Duration'), t('Status'), array('colspan' => 4, 'data' => ''));
  424. $output .= theme('table', array(
  425. 'header' => $headers,
  426. 'rows' => $rows[1],
  427. 'attributes' => array('id' => array('ultimate-cron-view'))
  428. ));
  429. $output .= '<div class="clear-block"></div>';
  430. }
  431. if ($overview['running']) {
  432. drupal_set_message(format_plural($overview['running'],
  433. '@jobs job is currently running',
  434. '@jobs jobs are currently running',
  435. array('@jobs' => $overview['running'])
  436. ));
  437. }
  438. if ($overview['warning']) {
  439. drupal_set_message(format_plural($overview['warning'],
  440. '@jobs job had warnings during its last run',
  441. '@jobs jobs had warnings during their last run',
  442. array('@jobs' => $overview['warning'])
  443. ), 'warning');
  444. }
  445. if ($overview['error']) {
  446. drupal_set_message(format_plural($overview['error'],
  447. '@jobs job had errors during its last run',
  448. '@jobs jobs had errors during their last run',
  449. array('@jobs' => $overview['error'])
  450. ), 'error');
  451. }
  452. return $output;
  453. }
  454. /**
  455. * Function log page.
  456. */
  457. function ultimate_cron_function_log_page($function) {
  458. $hooks = ultimate_cron_get_hooks();
  459. if (!isset($hooks[(string)$function])) {
  460. drupal_not_found();
  461. exit;
  462. }
  463. drupal_add_css(drupal_get_path('module', 'ultimate_cron') . '/css/ultimate_cron.admin.css');
  464. $header = array(
  465. array('data' => t('Start'), 'field' => 'start_stamp', 'sort' => 'DESC'),
  466. array('data' => t('End'), 'field' => 'end_stamp'),
  467. t('Duration'),
  468. t('Service host'),
  469. t('Status'),
  470. t('Message'),
  471. );
  472. drupal_set_title(check_plain($function));
  473. $query = db_select('ultimate_cron_log', 'l');
  474. $query = $query->condition('l.name', $function)
  475. ->extend('PagerDefault')
  476. ->limit(10)
  477. ->extend('TableSort')
  478. ->orderByHeader($header)
  479. ->fields('l', array('lid', 'name', 'start_stamp', 'end_stamp', 'service_host', 'exec_status', 'msg', 'severity'))
  480. ->orderBy('l.start_stamp', 'DESC');
  481. $logs = $query->execute()->fetchAll();
  482. $handle_prefix = variable_get('ultimate_cron_handle_prefix', ULTIMATE_CRON_HANDLE_PREFIX);
  483. $output = '';
  484. $rows = array();
  485. if (empty($_GET['page']) && $process = background_process_get_process($handle_prefix . $function)) {
  486. $data = array(
  487. array('class' => array('ultimate-cron-admin-start')),
  488. array('class' => array('ultimate-cron-admin-end')),
  489. array('class' => array('ultimate-cron-admin-duration')),
  490. array('class' => array('ultimate-cron-admin-service-host')),
  491. array('class' => array('ultimate-cron-admin-status ultimate-cron-admin-status-running')),
  492. array('class' => array('ultimate-cron-admin-message')),
  493. );
  494. $duration = time() - $process->start_stamp;
  495. $duration = gmdate('H:i:s', (int)$duration);
  496. $progress = progress_get_progress($handle_prefix . $function);
  497. if ($progress && $progress->progress > 0) {
  498. $duration .= sprintf(" (%d%%)", $progress->progress * 100);
  499. }
  500. $data[0]['data'] = format_date((int)$process->start_stamp, 'custom', 'Y-m-d H:i:s');
  501. $data[1]['data'] = t('N/A');
  502. $data[2]['data'] = $duration;
  503. $data[3]['data'] = $process->service_host ? $process->service_host : t('N/A');
  504. $data[4]['data'] = '<span>' . t('running') . '</span>';
  505. $data[5]['data'] = '';
  506. $rows[] = $data;
  507. }
  508. foreach ($logs as $log) {
  509. $log->function = $log->name;
  510. $log->status = $log->exec_status;
  511. $log->start = $log->start_stamp;
  512. $log->end = $log->end_stamp;
  513. $severity_type = $log->severity < 0 ? 'success' : ($log->severity >= WATCHDOG_NOTICE ? 'info' : ($log->severity >= WATCHDOG_WARNING ? 'warning' : 'error'));
  514. $css_status = $severity_type;
  515. $data = array(
  516. array('class' => array('ultimate-cron-admin-start')),
  517. array('class' => array('ultimate-cron-admin-end')),
  518. array('class' => array('ultimate-cron-admin-duration')),
  519. array('class' => array('ultimate-cron-admin-service-host')),
  520. array('class' => array('ultimate-cron-admin-status ultimate-cron-admin-status-' . $css_status)),
  521. array('class' => array('ultimate-cron-admin-message')),
  522. );
  523. $data[0]['data'] = format_date((int)$log->start, 'custom', 'Y-m-d H:i:s');
  524. $data[1]['data'] = format_date((int)$log->end, 'custom', 'Y-m-d H:i:s');
  525. $data[2]['data'] = gmdate('H:i:s', (int)($log->end - $log->start));
  526. $data[3]['data'] = $log->service_host ? $log->service_host : t('N/A');
  527. $data[4]['data'] = '<span>' . $log->status . '</span>';
  528. $data[5]['data'] = $log->msg;
  529. $rows[] = $data;
  530. }
  531. $output .= theme('table', array(
  532. 'header' => $header,
  533. 'rows' => $rows,
  534. 'attributes' => array('id' => 'ultimate-cron-view')
  535. ));
  536. $output .= theme('pager');
  537. return $output;
  538. }
  539. /**
  540. * Run a single function.
  541. *
  542. * @param $function
  543. * @return string
  544. * Output to page
  545. */
  546. function ultimate_cron_service_start($function) {
  547. $hooks = ultimate_cron_get_hooks();
  548. if (!isset($hooks[(string)$function])) {
  549. drupal_not_found();
  550. exit;
  551. }
  552. if ($modules = _ultimate_cron_incompatible_modules()) {
  553. drupal_set_message(t('%function could not start (incompatible module installed)', array('%function' => $function)), 'error');
  554. drupal_set_message(t('%modules is installed on the system, but is incompatible with Ultimate Cron.<br/>Please disable the conflicting modules.<br/>You might want to !url settings first.', array('%modules' => join(', ', $modules), '!url' => l(t('import'), 'admin/settings/cron/import'))), 'error');
  555. drupal_goto();
  556. }
  557. // When run manually don't double check the rules
  558. $hooks[$function]['skip_catch_up'] = TRUE;
  559. ultimate_cron_load_hook_data($hooks[$function]);
  560. $handle = ultimate_cron_run_hook($function, $hooks[$function]);
  561. if ($handle === FALSE) {
  562. drupal_set_message(t('%function could not start (already running?)', array('%function' => $function)), 'error');
  563. }
  564. elseif ($handle === NULL) {
  565. drupal_set_message(t('%function could not start (service unavailable)', array('%function' => $function)), 'error');
  566. }
  567. else {
  568. drupal_set_message(t('%function started', array('%function' => $function)));
  569. }
  570. drupal_goto();
  571. }
  572. /**
  573. * Enable/disable cron job
  574. * @param type $function
  575. * @param type $enabled
  576. */
  577. function ultimate_cron_service_enable($function, $enabled) {
  578. $conf = ultimate_cron_get_settings($function);
  579. $conf['enabled'] = $enabled;
  580. ultimate_cron_set_settings($function, $conf);
  581. drupal_goto();
  582. }
  583. /**
  584. * Send a message for all running processes.
  585. */
  586. function ultimate_cron_service_process_status() {
  587. $handle_prefix = variable_get('ultimate_cron_handle_prefix', ULTIMATE_CRON_HANDLE_PREFIX);
  588. $processes = array();
  589. $query = db_select('background_process', 'b')
  590. ->fields('b')
  591. ->condition('handle', $handle_prefix . '%', 'LIKE');
  592. foreach ($query->execute()->fetchAllAssoc('handle', PDO::FETCH_OBJ) as $process) {
  593. $process = BackgroundProcess::load($process);
  594. $name = preg_replace('/^' . $handle_prefix . '/', '', $process->handle);
  595. $processes[$name] = $process;
  596. $process->sendMessage('ultimateCronStatus');
  597. }
  598. return drupal_json_output(array('processes' => $processes));
  599. }
  600. /**
  601. * Import form.
  602. */
  603. function ultimate_cron_import_form() {
  604. $form = array();
  605. $options = array();
  606. if ($options) {
  607. $form['import']['module'] = array(
  608. '#type' => 'select',
  609. '#options' => $options,
  610. '#title' => t('Module'),
  611. '#description' => t('Module to import settings from'),
  612. );
  613. $form['import']['submit'] = array(
  614. '#type' => 'submit',
  615. '#submit' => array('ultimate_cron_import_form_submit'),
  616. '#value' => t('Import'),
  617. );
  618. }
  619. return $form;
  620. }
  621. /**
  622. * Submit handler for import.
  623. */
  624. function ultimate_cron_import_form_submit($form, &$form_state) {
  625. }
  626. /**
  627. * Helper function for links on cron list
  628. * @param $text
  629. * Text for link
  630. * @param $path
  631. * Path to link to
  632. * @return type
  633. */
  634. function _ultimate_cron_l($text, $path) {
  635. return l(
  636. '<span>' . t($text) . '</span>',
  637. $path,
  638. array(
  639. 'query' => drupal_get_destination(),
  640. 'html' => TRUE,
  641. )
  642. );
  643. }