job_scheduler.module 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. <?php
  2. /**
  3. * @file
  4. * job scheduler module.
  5. */
  6. /**
  7. * Collects and returns scheduler info.
  8. *
  9. * @see hook_cron_job_scheduler_info()
  10. *
  11. * @param $name
  12. * Name of the schedule
  13. * @return array
  14. * Information for the schedule if $name, all the information if not
  15. */
  16. function job_scheduler_info($name = NULL) {
  17. $info = &drupal_static(__FUNCTION__);
  18. if (!$info) {
  19. $info = module_invoke_all('cron_job_scheduler_info');
  20. drupal_alter('cron_job_scheduler_info', $info);
  21. }
  22. if ($name) {
  23. return isset($info[$name]) ? $info[$name] : NULL;
  24. }
  25. else {
  26. return $info;
  27. }
  28. }
  29. /**
  30. * Implements hook_cron().
  31. */
  32. function job_scheduler_cron() {
  33. // Reschedule all jobs if requested.
  34. if (variable_get('job_scheduler_rebuild_all', FALSE)) {
  35. foreach (job_scheduler_info() as $name => $info) {
  36. job_scheduler_rebuild_scheduler($name, $info);
  37. }
  38. variable_set('job_scheduler_rebuild_all', FALSE);
  39. return;
  40. }
  41. // Reschedule stuck periodic jobs after one hour.
  42. db_update('job_schedule')
  43. ->fields(array(
  44. 'scheduled' => 0,
  45. ))
  46. ->condition('scheduled', REQUEST_TIME - 3600, '<')
  47. ->condition('periodic', 1)
  48. ->execute();
  49. // Query and dispatch scheduled jobs.
  50. // Process a maximum of 200 jobs in a maximum of 30 seconds.
  51. $start = time();
  52. $total =
  53. $failed = 0;
  54. $jobs = db_select('job_schedule', NULL, array('fetch' => PDO::FETCH_ASSOC))
  55. ->fields('job_schedule')
  56. ->condition('scheduled', 0)
  57. ->condition('next', REQUEST_TIME, '<=')
  58. ->orderBy('next', 'ASC')
  59. ->range(0, 200)
  60. ->execute();
  61. foreach ($jobs as $job) {
  62. try {
  63. JobScheduler::get($job['name'])->dispatch($job);
  64. }
  65. catch (Exception $e) {
  66. watchdog('job_scheduler', $e->getMessage(), array(), WATCHDOG_ERROR);
  67. $failed++;
  68. // Drop jobs that have caused exceptions
  69. JobScheduler::get($job['name'])->remove($job);
  70. }
  71. $total++;
  72. if (time() > ($start + 30)) {
  73. break;
  74. }
  75. }
  76. // Leave a note on how much time we spent processing.
  77. watchdog('job_scheduler', 'Finished processing scheduled jobs (!time s, !total total, !failed failed).', array('!time' => format_interval(time() - $start), '!total' => $total, '!failed' => $failed));
  78. }
  79. /**
  80. * Implements hook_modules_enabled().
  81. */
  82. function job_scheduler_modules_enabled($modules) {
  83. job_scheduler_rebuild_all();
  84. }
  85. /**
  86. * Implements hook_modules_disabled().
  87. */
  88. function job_scheduler_modules_disabled($modules) {
  89. job_scheduler_rebuild_all();
  90. }
  91. /**
  92. * Rebuild scheduled information after enable/disable modules
  93. *
  94. * @todo What should we do about missing ones when disabling their module?
  95. */
  96. function job_scheduler_rebuild_all() {
  97. variable_set('job_scheduler_rebuild_all', TRUE);
  98. }
  99. /**
  100. * Rebuild a single scheduler
  101. */
  102. function job_scheduler_rebuild_scheduler($name, $info = NULL) {
  103. $info = $info ? $info : job_scheduler_info($name);
  104. if (!empty($info['jobs'])) {
  105. $scheduler = JobScheduler::get($name);
  106. foreach ($info['jobs'] as $job) {
  107. if (!$scheduler->check($job)) {
  108. $scheduler->set($job);
  109. }
  110. }
  111. }
  112. }
  113. /**
  114. * Implements hook_cron_queue_info().
  115. *
  116. * Provide queue worker information for jobs declared in
  117. * hook_cron_job_scheduler_info().
  118. */
  119. function job_scheduler_cron_queue_info() {
  120. $queue = array();
  121. foreach (job_scheduler_info() as $name => $info) {
  122. if (!empty($info['jobs']) && !empty($info['queue name'])) {
  123. $queue[$info['queue name']] = array(
  124. 'worker callback' => 'job_scheduler_cron_queue_worker',
  125. 'time' => 60, // Some reasonable default as we don't know
  126. );
  127. }
  128. }
  129. return $queue;
  130. }
  131. /**
  132. * Execute job worker from queue
  133. *
  134. * Providing our own worker has the advantage that we can reschedule the job or take care of cleanup
  135. * Note that as we run the execute() action, the job won't be queued again this time.
  136. */
  137. function job_scheduler_cron_queue_worker($job) {
  138. try {
  139. JobScheduler::get($job['name'])->execute($job);
  140. }
  141. catch (Exception $e) {
  142. watchdog('job_scheduler', $e->getMessage(), array(), WATCHDOG_ERROR);
  143. // Drop jobs that have caused exceptions
  144. JobScheduler::get($job['name'])->remove($job);
  145. }
  146. }