Project

General

Profile

Paste
Download (7.1 KB) Statistics
| Branch: | Revision:

root / drupal7 / sites / all / modules / job_scheduler / job_scheduler.module @ 082b75eb

1
<?php
2

    
3
/**
4
 * @file
5
 * Main file for the Job Scheduler.
6
 */
7

    
8
/**
9
 * Implements hook_help().
10
 *
11
 * @codingStandardsIgnoreStart
12
 */
13
function job_scheduler_help($path, $arg) {
14
  switch ($path) {
15
    case 'admin/help#job_scheduler':
16
      $output = '<h3>' . t('About') . '</h3>';
17
      $output .= '<p>' . t('Simple API for scheduling tasks once at a predetermined time or periodically at a fixed interval.') . '</p>';
18
      $output .= '<h3>' . t('Usage') . '</h3>';
19
      $output .= '<p>' . t('Declare scheduler.') . '</p>';
20
      $output .= '<xmp>' .
21
'function example_cron_job_scheduler_info() {
22
  $schedulers - array();
23
  $schedulers[\'example_unpublish\'] - array(
24
    \'worker callback\' -> \'example_unpublish_nodes\',
25
  );
26
  return $schedulers;
27
}'
28
. '</xmp>';
29
      
30
      $output .= '<p>' . t('Add a job.') . '</p>';
31
      $output .= '<xmp>' .
32
'$job - array(
33
  \'type\' -> \'story\',
34
  \'id\' -> 12,
35
  \'period\' -> 3600,
36
  \'periodic\' -> TRUE,
37
);
38
JobScheduler::get(\'example_unpublish\')->set($job);'
39
. '</xmp>';
40
      
41
      //
42
      
43
    $output .= '<p>' . t('Work off a job.') . '</p>';
44
    $output .= '<xmp>' .
45
'function example_unpublish_nodes($job) {
46
  // Do stuff.
47
}'
48
    . '</xmp>';
49
      
50
    $output .= '<p>' . t('Remove a job.') . '</p>';
51
      $output .= '<xmp>' .
52
'$job - array(
53
  \'type\' -> \'story\',
54
  \'id\' -> 12,
55
);
56
JobScheduler::get(\'example_unpublish\')->remove($job);'
57
    . '</xmp>';
58
      
59
      $output .= '<p>' . t('Optionally jobs can declared together with a schedule in a: hook_cron_job_scheduler_info().') . '</p>';
60
      $output .= '<xmp>' .
61
'function example_cron_job_scheduler_info() {
62
  $schedulers - array();
63
  $schedulers[\'example_unpublish\'] - array(
64
    \'worker callback\' -> \'example_unpublish_nodes\',
65
    \'jobs\' -> array(
66
      array(
67
        \'type\' -> \'story\',
68
        \'id\' -> 12,
69
        \'period\' -> 3600,
70
        \'periodic\' -> TRUE,
71
      ),
72
    )
73
  );
74
  return $schedulers;
75
}'
76
      . '</xmp>';
77
      
78
      $output .= '<p>' . t("Jobs can have a 'crontab' instead of a period. Crontab syntax are Unix-like formatted crontab lines.") . '</p>';
79
      $output .= '<p>' . t('Example of job with crontab.') . '</p>';
80
      $output .= '<p>' . t("This will create a job that will be triggered from monday to friday, from january to july, every two hours.") . '</p>';
81
      
82
      
83
      $output .= '<xmp>' .
84
'function example_cron_job_scheduler_info() {
85
  $schedulers - array();
86
  $schedulers[\'example_unpublish\'] - array(
87
    \'worker callback\' -> \'example_unpublish_nodes\',
88
    \'jobs\' -> array(
89
      array(
90
        \'type\' -> \'story\',
91
        \'id\' -> 12,
92
        \'crontab\' -> \'0 */2 * january-july mon-fri\',
93
        \'periodic\' -> TRUE,
94
      ),
95
    )
96
  );
97
  return $schedulers;
98
}'
99
. '</xmp>';
100
      
101
      $output .= '<p>' . t('Read more about crontab syntax: <a href="@url_crontab_sintax" target="blank">@url_crontab_sintax</a>', array('@url_crontab_sintax' => 'http://linux.die.net/man/5/crontab')) . '</p>';
102
      
103
      
104
      return $output;
105
  }
106
}
107
// @codingStandardsIgnoreEnd
108

    
109
/**
110
 * Collects and returns scheduler info.
111
 *
112
 * @param string $name
113
 *   Name of the schedule.
114
 *
115
 * @see hook_cron_job_scheduler_info()
116
 *
117
 * @return array
118
 *   Information for the schedule if $name, all the information if not
119
 */
120
function job_scheduler_info($name = NULL) {
121
  $info = &drupal_static(__FUNCTION__);
122
  if (!$info) {
123
    $info = module_invoke_all('cron_job_scheduler_info');
124
    drupal_alter('cron_job_scheduler_info', $info);
125
  }
126
  if ($name) {
127
    return isset($info[$name]) ? $info[$name] : NULL;
128
  }
129
  else {
130
    return $info;
131
  }
132
}
133

    
134
/**
135
 * Implements hook_cron().
136
 */
137
function job_scheduler_cron() {
138
  // Reschedule all jobs if requested.
139
  if (variable_get('job_scheduler_rebuild_all', FALSE)) {
140
    foreach (job_scheduler_info() as $name => $info) {
141
      job_scheduler_rebuild_scheduler($name, $info);
142
    }
143
    variable_set('job_scheduler_rebuild_all', FALSE);
144
    return;
145
  }
146

    
147
  // Reschedule stuck periodic jobs after one hour.
148
  db_update('job_schedule')
149
    ->fields(array(
150
      'scheduled' => 0,
151
    ))
152
    ->condition('scheduled', REQUEST_TIME - 3600, '<')
153
    ->condition('periodic', 1)
154
    ->execute();
155

    
156
  // Query and dispatch scheduled jobs.
157
  // Process a maximum of 200 jobs in a maximum of 30 seconds.
158
  $start = time();
159
  $total = $failed = 0;
160
  $jobs = db_select('job_schedule', NULL, array('fetch' => PDO::FETCH_ASSOC))
161
    ->fields('job_schedule')
162
    ->condition('scheduled', 0)
163
    ->condition('next', REQUEST_TIME, '<=')
164
    ->orderBy('next', 'ASC')
165
    ->range(0, 200)
166
    ->execute();
167
  foreach ($jobs as $job) {
168
    $job['data'] = unserialize($job['data']);
169
    try {
170
      JobScheduler::get($job['name'])->dispatch($job);
171
    }
172
    catch (Exception $e) {
173
      watchdog('job_scheduler', $e->getMessage(), array(), WATCHDOG_ERROR);
174
      $failed++;
175
      // Drop jobs that have caused exceptions.
176
      JobScheduler::get($job['name'])->remove($job);
177
    }
178
    $total++;
179
    if (time() > ($start + 30)) {
180
      break;
181
    }
182
  }
183

    
184
  // If any jobs were processed, log how much time we spent processing.
185
  if ($total || $failed) {
186
    watchdog('job_scheduler', 'Finished processing scheduled jobs (!time, !total total, !failed failed).', array(
187
      '!time' => format_interval(time() - $start),
188
      '!total' => $total,
189
      '!failed' => $failed,
190
    ));
191
  }
192
}
193

    
194
/**
195
 * Implements hook_modules_enabled().
196
 */
197
function job_scheduler_modules_enabled($modules) {
198
  job_scheduler_rebuild_all();
199
}
200

    
201
/**
202
 * Implements hook_modules_disabled().
203
 */
204
function job_scheduler_modules_disabled($modules) {
205
  job_scheduler_rebuild_all();
206
}
207

    
208
/**
209
 * Rebuild scheduled information after enable/disable modules.
210
 *
211
 * @todo What should we do about missing ones when disabling their module?
212
 */
213
function job_scheduler_rebuild_all() {
214
  variable_set('job_scheduler_rebuild_all', TRUE);
215
}
216

    
217
/**
218
 * Rebuild a single scheduler.
219
 */
220
function job_scheduler_rebuild_scheduler($name, $info) {
221
  if (!empty($info['jobs'])) {
222
    $scheduler = JobScheduler::get($name);
223
    foreach ($info['jobs'] as $job) {
224
      if (!$scheduler->check($job)) {
225
        $scheduler->set($job);
226
      }
227
    }
228
  }
229
}
230

    
231
/**
232
 * Implements hook_cron_queue_info().
233
 *
234
 * Provide queue worker information for jobs declared in
235
 * hook_cron_job_scheduler_info().
236
 */
237
function job_scheduler_cron_queue_info() {
238
  $queue = array();
239
  foreach (job_scheduler_info() as $info) {
240
    if (!empty($info['jobs']) && !empty($info['queue name'])) {
241
      $queue[$info['queue name']] = array(
242
        'worker callback' => 'job_scheduler_cron_queue_worker',
243
        // Some reasonable default as we don't know.
244
        'time' => 60,
245
      );
246
    }
247
  }
248
  return $queue;
249
}
250

    
251
/**
252
 * Execute job worker from queue.
253
 *
254
 * Providing our own worker has the advantage that we can reschedule the job or
255
 * take care of cleanup
256
 * Note that as we run the execute() action, the job won't be queued again this
257
 * time.
258
 */
259
function job_scheduler_cron_queue_worker($job) {
260
  try {
261
    JobScheduler::get($job['name'])->execute($job);
262
  }
263
  catch (Exception $e) {
264
    watchdog('job_scheduler', $e->getMessage(), array(), WATCHDOG_ERROR);
265
    // Drop jobs that have caused exceptions.
266
    JobScheduler::get($job['name'])->remove($job);
267
  }
268
}