ultimate_cron.admin.inc 26 KB

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