first import
This commit is contained in:
33
sites/all/modules/job_scheduler/CHANGELOG.txt
Normal file
33
sites/all/modules/job_scheduler/CHANGELOG.txt
Normal file
@@ -0,0 +1,33 @@
|
||||
|
||||
Job Scheduler 7.x xxxxxxxxxxxxxxxxxxxxxxx
|
||||
-----------------------------------------
|
||||
|
||||
- Jose Reyero: Auto schedule jobs.
|
||||
- Jose Reyero: Reschedule jobs from hook implementation.
|
||||
- Jose Reyero: Provide crontab style scheduling.
|
||||
- Jose Reyero: Provide triggers.
|
||||
|
||||
Job Scheduler 7.x 2.0 Alpha 1, 2010-09-29
|
||||
-----------------------------------------
|
||||
|
||||
- #922702: Fix Drupal Queue integration.
|
||||
Note: JobScheduler API has changed significantly, API users must declare
|
||||
callbacks with hook_cron_job_scheduler_info() and the call signature for
|
||||
managing jobs has changed. Please review README.txt.
|
||||
- Upgrade to Drupal 7.
|
||||
|
||||
Job Scheduler 6.x 1.0 Beta 3, 2010-09-14
|
||||
----------------------------------------
|
||||
|
||||
- Fix notice.
|
||||
|
||||
Job Scheduler 6.x 1.0 Beta 2, 2010-09-12
|
||||
----------------------------------------
|
||||
|
||||
- Replace FEEDS_REQUEST_TIME with JOB_SCHEDULER_REQUEST_TIME.
|
||||
- Fix indexes.
|
||||
|
||||
Job Scheduler 6.x 1.0 Beta 1, 2010-09-11
|
||||
----------------------------------------
|
||||
|
||||
- Initial commit: schedule execution at predetermined time, periodic scheduling.
|
226
sites/all/modules/job_scheduler/JobScheduler.inc
Normal file
226
sites/all/modules/job_scheduler/JobScheduler.inc
Normal file
@@ -0,0 +1,226 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* JobScheduler class.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Use to make Job Scheduler exceptions identifiable by type.
|
||||
*/
|
||||
class JobSchedulerException extends Exception {}
|
||||
|
||||
/**
|
||||
* Manage scheduled jobs.
|
||||
*/
|
||||
class JobScheduler {
|
||||
/**
|
||||
* The name of this scheduler.
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* Produces a single instance of JobScheduler for a schedule name.
|
||||
*/
|
||||
public static function get($name) {
|
||||
static $schedulers;
|
||||
// Instantiante a new scheduler for $name if we haven't done so yet.
|
||||
if (!isset($schedulers[$name])) {
|
||||
$class = variable_get('job_scheduler_class_' . $name, 'JobScheduler');
|
||||
$schedulers[$name] = new $class($name);
|
||||
}
|
||||
return $schedulers[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JobScheduler object.
|
||||
*/
|
||||
protected function __construct($name) {
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns scheduler info.
|
||||
*
|
||||
* @see hook_cron_job_scheduler_info()
|
||||
*
|
||||
* @throws JobSchedulerException.
|
||||
*/
|
||||
public function info() {
|
||||
if ($info = job_scheduler_info($this->name)) {
|
||||
return $info;
|
||||
}
|
||||
throw new JobSchedulerException('Could not find Job Scheduler cron information for ' . check_plain($this->name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a job to the schedule, replace any existing job.
|
||||
*
|
||||
* A job is uniquely identified by $job = array(type, id).
|
||||
*
|
||||
* @param $job
|
||||
* An array that must contain the following keys:
|
||||
* 'type' - A string identifier of the type of job.
|
||||
* 'id' - A numeric identifier of the job.
|
||||
* 'period' - The time when the task should be executed.
|
||||
* 'periodic' - True if the task should be repeated periodically.
|
||||
*
|
||||
* @code
|
||||
* function worker_callback($job) {
|
||||
* // Work off job.
|
||||
* // Set next time to be called. If this portion of the code is not
|
||||
* // reached for some reason, the scheduler will keep periodically invoking
|
||||
* // the callback() with the period value initially specified.
|
||||
* $scheduler->set($job);
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
public function set($job) {
|
||||
$job['name'] = $this->name;
|
||||
$job['last'] = REQUEST_TIME;
|
||||
if (!empty($job['crontab'])) {
|
||||
$crontab = new JobSchedulerCronTab($job['crontab']);
|
||||
$job['next'] = $crontab->nextTime(REQUEST_TIME);
|
||||
}
|
||||
else {
|
||||
$job['next'] = REQUEST_TIME + $job['period'];
|
||||
}
|
||||
$job['scheduled'] = 0;
|
||||
$this->remove($job);
|
||||
drupal_write_record('job_schedule', $job);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reserve a job.
|
||||
*/
|
||||
protected function reserve($job) {
|
||||
$job['name'] = $this->name;
|
||||
$job['scheduled'] =
|
||||
$job['last'] = REQUEST_TIME;
|
||||
$job['next'] = $job['period'] + REQUEST_TIME;
|
||||
drupal_write_record('job_schedule', $job, array('name', 'type', 'id'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a job from the schedule, replace any existing job.
|
||||
*
|
||||
* A job is uniquely identified by $job = array(type, id).
|
||||
*/
|
||||
public function remove($job) {
|
||||
db_delete('job_schedule')
|
||||
->condition('name', $this->name)
|
||||
->condition('type', $job['type'])
|
||||
->condition('id', isset($job['id']) ? $job['id'] : 0)
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all jobs for a given type.
|
||||
*/
|
||||
public function removeAll($type) {
|
||||
db_delete('job_schedule')
|
||||
->condition('name', $this->name)
|
||||
->condition('type', $type)
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches a job.
|
||||
*
|
||||
* Executes a worker callback or if schedule declares a queue name, queues a
|
||||
* job for execution.
|
||||
*
|
||||
* @param $job
|
||||
* A $job array as passed into set() or read from job_schedule table.
|
||||
*
|
||||
* @throws Exception
|
||||
* Exceptions thrown by code called by this method are passed on.
|
||||
*/
|
||||
public function dispatch($job) {
|
||||
$info = $this->info();
|
||||
if (!$job['periodic']) {
|
||||
$this->remove($job);
|
||||
}
|
||||
if (!empty($info['queue name'])) {
|
||||
if (DrupalQueue::get($info['queue name'])->createItem($job)) {
|
||||
$this->reserve($job);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$this->execute($job);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a job that
|
||||
*
|
||||
* @param $job
|
||||
* A $job array as passed into set() or read from job_schedule table.
|
||||
*
|
||||
* @throws Exception
|
||||
* Exceptions thrown by code called by this method are passed on.
|
||||
*/
|
||||
public function execute($job) {
|
||||
$info = $this->info();
|
||||
// If the job is periodic, re-schedule it before calling the worker, just in case
|
||||
if ($job['periodic']) {
|
||||
$job['last'] = REQUEST_TIME;
|
||||
$this->reschedule($job);
|
||||
}
|
||||
if (function_exists($info['worker callback'])) {
|
||||
call_user_func($info['worker callback'], $job);
|
||||
}
|
||||
else {
|
||||
// @todo If worker doesn't exist anymore we should do something about it, remove and throw exception?
|
||||
$this->remove($job);
|
||||
throw new JobSchedulerException('Could not find worker callback function: ' . $info['worker callback']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-schedule a job if intended to run again
|
||||
*
|
||||
* (If cannot determine the next time, drop the job)
|
||||
*/
|
||||
public function reschedule($job) {
|
||||
$job['scheduled'] = 0;
|
||||
if (!empty($job['crontab'])) {
|
||||
$crontab = new JobSchedulerCronTab($job['crontab']);
|
||||
$job['next'] = $crontab->nextTime($job['last']);
|
||||
}
|
||||
else {
|
||||
$job['next'] = $job['last'] + $job['period'];
|
||||
}
|
||||
|
||||
if ($job['next']) {
|
||||
drupal_write_record('job_schedule', $job, array('item_id'));
|
||||
}
|
||||
else {
|
||||
// If no next time, it may mean it wont run again the next year (crontab)
|
||||
$this->remove($job);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a job exists in the queue and update its parameters if so
|
||||
*/
|
||||
public function check($job) {
|
||||
$job += array('id' => 0, 'period' => 0, 'crontab' => '');
|
||||
$existing = db_select('job_schedule')
|
||||
->fields('job_schedule')
|
||||
->condition('name', $this->name)
|
||||
->condition('type', $job['type'])
|
||||
->condition('id', $job['id'])
|
||||
->execute()
|
||||
->fetchAssoc();
|
||||
// If existing, and changed period or crontab, we need to reschedule the job
|
||||
if ($existing) {
|
||||
if ($job['period'] != $existing['period'] || $job['crontab'] != $existing['crontab']) {
|
||||
$existing['period'] = $job['period'];
|
||||
$existing['crontab'] = $job['crontab'];
|
||||
$this->reschedule($existing);
|
||||
}
|
||||
return $existing;
|
||||
}
|
||||
}
|
||||
}
|
279
sites/all/modules/job_scheduler/JobSchedulerCronTab.inc
Normal file
279
sites/all/modules/job_scheduler/JobSchedulerCronTab.inc
Normal file
@@ -0,0 +1,279 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* JobSchedulerCronTab class.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Jose's cron tab parser = Better try only simple crontab strings.
|
||||
*
|
||||
* Usage:
|
||||
* // Run 23 minutes after midn, 2am, 4am ..., everyday
|
||||
* $crontab = new JobSchedulerCronTab('23 0-23/2 * * *');
|
||||
* // When this needs to run next, from current time?
|
||||
* $next_time = $crontab->nextTime(time());
|
||||
*
|
||||
* I hate Sundays.
|
||||
*/
|
||||
class JobSchedulerCronTab {
|
||||
// Original crontab elements
|
||||
public $crontab;
|
||||
// Parsed numeric values indexed by type
|
||||
public $cron;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* About crontab strings, see all about possible formats
|
||||
* http://linux.die.net/man/5/crontab
|
||||
*
|
||||
* @param $crontab string
|
||||
* Crontab text line: minute hour day-of-month month day-of-week
|
||||
*/
|
||||
public function __construct($crontab) {
|
||||
$this->crontab = $crontab;
|
||||
$this->cron = is_array($crontab) ? $this->values($crontab) : $this->parse($crontab);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse full crontab string into an array of type => values
|
||||
*
|
||||
* Note this one is static and can be used to validate values
|
||||
*/
|
||||
public static function parse($crontab) {
|
||||
// Crontab elements, names match PHP date indexes (getdate)
|
||||
$keys = array('minutes', 'hours', 'mday', 'mon', 'wday');
|
||||
// Replace multiple spaces by single space
|
||||
$crontab = preg_replace('/(\s+)/', ' ', $crontab);
|
||||
// Expand into elements and parse all
|
||||
$values = explode(' ', trim($crontab));
|
||||
return self::values($values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse array of values, check whether this is valid
|
||||
*/
|
||||
public static function values($array) {
|
||||
if (count($array) == 5) {
|
||||
$values = array_combine(array('minutes', 'hours', 'mday', 'mon', 'wday'), array_map('trim', $array));
|
||||
$elements = array();
|
||||
foreach ($values as $type => $string) {
|
||||
$elements[$type] = self::parseElement($type, $string, TRUE);
|
||||
}
|
||||
// Return only if we have the right number of elements
|
||||
// Dangerous means works running every second or things like that.
|
||||
if (count(array_filter($elements)) == 5) {
|
||||
return $elements;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the next occurrence within the next year as unix timestamp
|
||||
*
|
||||
* @param $start_time timestamp
|
||||
* Starting time
|
||||
*/
|
||||
public function nextTime($start_time = NULL, $limit = 366) {
|
||||
$start_time = isset($start_time) ? $start_time : time();
|
||||
$start_date = getdate($start_time); // Get minutes, hours, mday, wday, mon, year
|
||||
if ($date = $this->nextDate($start_date, $limit)) {
|
||||
return mktime($date['hours'], $date['minutes'], 0, $date['mon'], $date['mday'], $date['year']);
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the next occurrence within the next year as a date array,
|
||||
*
|
||||
* @see getdate()
|
||||
*
|
||||
* @param $date
|
||||
* Date array with: 'mday', 'mon', 'year', 'hours', 'minutes'
|
||||
*/
|
||||
public function nextDate($date, $limit = 366) {
|
||||
$date['seconds'] = 0;
|
||||
// It is possible that the current date doesn't match
|
||||
if ($this->checkDay($date) && ($nextdate = $this->nextHour($date))) {
|
||||
return $nextdate;
|
||||
}
|
||||
elseif ($nextdate = $this->nextDay($date, $limit)) {
|
||||
return $nextdate;
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether date's day is a valid one
|
||||
*/
|
||||
protected function checkDay($date) {
|
||||
foreach (array('wday', 'mday', 'mon') as $key) {
|
||||
if (!in_array($date[$key], $this->cron[$key])) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the next day from date that matches with cron parameters
|
||||
*
|
||||
* Maybe it's possible that it's within the next years, maybe no day of a year matches all conditions.
|
||||
* However, to prevent infinite loops we restrict it to the next year.
|
||||
*/
|
||||
protected function nextDay($date, $limit = 366) {
|
||||
$i = 0; // Safety check, we love infinite loops...
|
||||
while ($i++ <= $limit) {
|
||||
// This should fix values out of range, like month > 12, day > 31....
|
||||
// So we can trust we get the next valid day, can't we?
|
||||
$time = mktime(0, 0, 0, $date['mon'], $date['mday'] + 1, $date['year']);
|
||||
$date = getdate($time);
|
||||
if ($this->checkDay($date)) {
|
||||
$date['hours'] = reset($this->cron['hours']);
|
||||
$date['minutes'] = reset($this->cron['minutes']);
|
||||
return $date;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Find the next available hour within the same day
|
||||
*/
|
||||
protected function nextHour($date) {
|
||||
$cron = $this->cron;
|
||||
while ($cron['hours']) {
|
||||
$hour = array_shift($cron['hours']);
|
||||
// Current hour; next minute.
|
||||
if ($date['hours'] == $hour) {
|
||||
foreach ($cron['minutes'] as $minute) {
|
||||
if ($date['minutes'] < $minute) {
|
||||
$date['hours'] = $hour;
|
||||
$date['minutes'] = $minute;
|
||||
return $date;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Next hour; first avaiable minute.
|
||||
elseif ($date['hours'] < $hour) {
|
||||
$date['hours'] = $hour;
|
||||
$date['minutes'] = reset($cron['minutes']);
|
||||
return $date;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse each text element. Recursive up to some point...
|
||||
*/
|
||||
protected static function parseElement($type, $string, $translate = FALSE) {
|
||||
$string = trim($string);
|
||||
if ($translate) {
|
||||
$string = self::translateNames($type, $string);
|
||||
}
|
||||
if ($string === '*') {
|
||||
// This means all possible values, return right away, no need to double check
|
||||
return self::possibleValues($type);
|
||||
}
|
||||
elseif (strpos($string, '/')) {
|
||||
// Multiple. Example */2, for weekday will expand into 2, 4, 6
|
||||
list($values, $multiple) = explode('/', $string);
|
||||
$values = self::parseElement($type, $values);
|
||||
foreach ($values as $value) {
|
||||
if (!($value % $multiple)) {
|
||||
$range[] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif (strpos($string, ',')) {
|
||||
// Now process list parts, expand into items, process each and merge back
|
||||
$list = explode(',', $string);
|
||||
$range = array();
|
||||
foreach ($list as $item) {
|
||||
if ($values = self::parseElement($type, $item)) {
|
||||
$range = array_merge($range, $values);
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif (strpos($string, '-')) {
|
||||
// This defines a range. Example 1-3, will expand into 1,2,3
|
||||
list($start, $end) = explode('-', $string);
|
||||
// Double check the range is within possible values
|
||||
$range = range($start, $end);
|
||||
}
|
||||
elseif (is_numeric($string)) {
|
||||
// This looks like a single number, double check it's int
|
||||
$range = array((int)$string);
|
||||
}
|
||||
|
||||
// Return unique sorted values and double check they're within possible values
|
||||
if (!empty($range)) {
|
||||
$range = array_intersect(array_unique($range), self::possibleValues($type));
|
||||
sort($range);
|
||||
// Sunday validation. We need cron values to match PHP values, thus week day 7 is not allowed, must be 0
|
||||
if ($type == 'wday' && in_array(7, $range)) {
|
||||
array_pop($range);
|
||||
array_unshift($range, 0);
|
||||
}
|
||||
return $range;
|
||||
}
|
||||
else {
|
||||
// No match found for this one, will produce an error with validation
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get values for each type
|
||||
*/
|
||||
public static function possibleValues($type) {
|
||||
switch ($type) {
|
||||
case 'minutes':
|
||||
return range(0, 59);
|
||||
case 'hours':
|
||||
return range(0, 23);
|
||||
case 'mday':
|
||||
return range(1, 31);
|
||||
case 'mon':
|
||||
return range(1, 12);
|
||||
case 'wday':
|
||||
// These are PHP values, not *nix ones
|
||||
return range(0, 6);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace element names by values
|
||||
*/
|
||||
public static function translateNames($type, $string) {
|
||||
switch ($type) {
|
||||
case 'wday':
|
||||
$replace = array_merge(
|
||||
// Tricky, tricky, we need sunday to be zero at the beginning of a range, but 7 at the end
|
||||
array('-sunday' => '-7', '-sun' => '-7', 'sunday-' => '0-', 'sun-' => '0-'),
|
||||
array_flip(array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday')),
|
||||
array_flip(array('sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'))
|
||||
);
|
||||
break;
|
||||
case 'mon':
|
||||
$replace = array_merge(
|
||||
array_flip(array('nomonth1', 'january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december')),
|
||||
array_flip(array('nomonth2', 'jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec')),
|
||||
array('sept' => 9)
|
||||
);
|
||||
break;
|
||||
}
|
||||
if (empty($replace)) {
|
||||
return $string;
|
||||
}
|
||||
else {
|
||||
return strtr($string, $replace);
|
||||
}
|
||||
}
|
||||
}
|
339
sites/all/modules/job_scheduler/LICENSE.txt
Normal file
339
sites/all/modules/job_scheduler/LICENSE.txt
Normal file
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
132
sites/all/modules/job_scheduler/README.txt
Normal file
132
sites/all/modules/job_scheduler/README.txt
Normal file
@@ -0,0 +1,132 @@
|
||||
|
||||
Job Scheduler
|
||||
=============
|
||||
|
||||
Simple API for scheduling tasks once at a predetermined time or periodically at
|
||||
a fixed interval.
|
||||
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Declare scheduler.
|
||||
|
||||
function example_cron_job_scheduler_info() {
|
||||
$schedulers = array();
|
||||
$schedulers['example_unpublish'] = array(
|
||||
'worker callback' => 'example_unpublish_nodes',
|
||||
);
|
||||
return $schedulers;
|
||||
}
|
||||
|
||||
Add a job.
|
||||
|
||||
$job = array(
|
||||
'type' => 'story',
|
||||
'id' => 12,
|
||||
'period' => 3600,
|
||||
'periodic' => TRUE,
|
||||
);
|
||||
JobScheduler::get('example_unpublish')->set($job);
|
||||
|
||||
Work off a job.
|
||||
|
||||
function example_unpublish_nodes($job) {
|
||||
// Do stuff.
|
||||
}
|
||||
|
||||
Remove a job.
|
||||
|
||||
$job = array(
|
||||
'type' => 'story',
|
||||
'id' => 12,
|
||||
);
|
||||
JobScheduler::get('example_unpublish')->remove($job);
|
||||
|
||||
Optionally jobs can declared together with a schedule in a hook_cron_job_scheduler_info().
|
||||
|
||||
function example_cron_job_scheduler_info() {
|
||||
$schedulers = array();
|
||||
$schedulers['example_unpublish'] = array(
|
||||
'worker callback' => 'example_unpublish_nodes',
|
||||
'jobs' => array(
|
||||
array('type' => 'story', 'id' => 12, 'period' => 3600, 'periodic' => TRUE),
|
||||
)
|
||||
);
|
||||
return $schedulers;
|
||||
}
|
||||
|
||||
Jobs can have a 'crontab' instead of a period. Crontab syntax are Unix-like formatted crontab lines.
|
||||
Example of job with crontab.
|
||||
|
||||
// This will create a job that will be triggered from monday to friday, from january to july, every two hours
|
||||
function example_cron_job_scheduler_info() {
|
||||
$schedulers = array();
|
||||
$schedulers['example_unpublish'] = array(
|
||||
'worker callback' => 'example_unpublish_nodes',
|
||||
'jobs' => array(
|
||||
array('type' => 'story', 'id' => 12, 'crontab' => '0 */2 * january-july mon-fri', 'periodic' => TRUE),
|
||||
)
|
||||
);
|
||||
return $schedulers;
|
||||
}
|
||||
|
||||
Read more about crontab syntax, http://linux.die.net/man/5/crontab
|
||||
|
||||
Drupal Queue integration
|
||||
========================
|
||||
|
||||
Optionally, at the scheduled time Job Scheduler can queue a job for execution,
|
||||
rather than executing the job directly. This is useful when many jobs need to
|
||||
be executed or when the job's expected execution time is very long.
|
||||
|
||||
More information on Drupal Queue: http://api.drupal.org/api/group/queue/7
|
||||
|
||||
Instead of declaring a worker callback, declare a queue name.
|
||||
|
||||
function example_cron_job_scheduler_info() {
|
||||
$schedulers = array();
|
||||
$schedulers['example_unpublish'] = array(
|
||||
'queue name' => 'example_unpublish_queue',
|
||||
);
|
||||
return $schedulers;
|
||||
}
|
||||
|
||||
This of course assumes that you have declared a queue. Notice how in this
|
||||
pattern the queue callback contains the actual worker callback.
|
||||
|
||||
function example_cron_queue_info() {
|
||||
$schedulers = array();
|
||||
$schedulers['example_unpublish_queue'] = array(
|
||||
'worker callback' => 'example_unpublish_nodes',
|
||||
);
|
||||
return $schedulers;
|
||||
}
|
||||
|
||||
|
||||
Work off a job: when using a queue, Job Scheduler reserves a job for one hour
|
||||
giving the queue time to work off a job before it reschedules it. This means
|
||||
that the worker callback needs to reset the job's schedule flag in order to
|
||||
allow renewed scheduling.
|
||||
|
||||
function example_unpublish_nodes($job) {
|
||||
// Do stuff.
|
||||
// Set the job again so that its reserved flag is reset.
|
||||
JobScheduler::get('example_unpublish')->set($job);
|
||||
}
|
||||
|
||||
Example
|
||||
=======
|
||||
|
||||
See Feeds module.
|
||||
|
||||
|
||||
Hidden settings
|
||||
===============
|
||||
|
||||
Hidden settings are variables that you can define by adding them to the $conf
|
||||
array in your settings.php file.
|
||||
|
||||
Name: 'job_scheduler_class_' . $name
|
||||
Default: 'JobScheduler'
|
||||
Description: The class to use for managing a particular schedule.
|
50
sites/all/modules/job_scheduler/job_scheduler.api.php
Normal file
50
sites/all/modules/job_scheduler/job_scheduler.api.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* API documentation for hooks.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Declare job scheduling holding items that need to be run periodically.
|
||||
*
|
||||
* @return
|
||||
* An associative array where the key is the queue name and the value is
|
||||
* again an associative array. Possible keys are:
|
||||
* - 'worker callback': The name of the function to call. It will be called
|
||||
* at schedule time.
|
||||
* - 'queue name': The name of the queue to use to queue this task. Must
|
||||
* contain a valid queue name, declared by hook_cron_queue_info().
|
||||
* If queue name is given, worker callback will be ignored.
|
||||
*
|
||||
* @see hook_cron_job_scheduler_info_alter()
|
||||
* @see hook_cron_queue_info()
|
||||
* @see hook_cron_queue_info_alter()
|
||||
*/
|
||||
function hook_cron_job_scheduler_info() {
|
||||
$info = array();
|
||||
$info['example_reset'] = array(
|
||||
'worker callback' => 'example_cache_clear_worker',
|
||||
);
|
||||
$info['example_import'] = array(
|
||||
'queue name' => 'example_import_queue',
|
||||
);
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter cron queue information before cron runs.
|
||||
*
|
||||
* Called by drupal_cron_run() to allow modules to alter cron queue settings
|
||||
* before any jobs are processesed.
|
||||
*
|
||||
* @param array $info
|
||||
* An array of cron schedule information.
|
||||
*
|
||||
* @see hook_cron_queue_info()
|
||||
* @see drupal_cron_run()
|
||||
*/
|
||||
function hook_cron_job_scheduler_info_alter(&$info) {
|
||||
// Replace the default callback 'example_cache_clear_worker'
|
||||
$info['example_reset']['worker callback'] = 'my_custom_reset';
|
||||
}
|
15
sites/all/modules/job_scheduler/job_scheduler.info
Normal file
15
sites/all/modules/job_scheduler/job_scheduler.info
Normal file
@@ -0,0 +1,15 @@
|
||||
name = Job Scheduler
|
||||
description = Scheduler API
|
||||
files[] = job_scheduler.module
|
||||
files[] = job_scheduler.install
|
||||
files[] = JobScheduler.inc
|
||||
files[] = JobSchedulerCronTab.inc
|
||||
core = 7.x
|
||||
php = 5.2
|
||||
|
||||
; Information added by drupal.org packaging script on 2012-05-08
|
||||
version = "7.x-2.0-alpha3"
|
||||
core = "7.x"
|
||||
project = "job_scheduler"
|
||||
datestamp = "1336466457"
|
||||
|
180
sites/all/modules/job_scheduler/job_scheduler.install
Normal file
180
sites/all/modules/job_scheduler/job_scheduler.install
Normal file
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Schema definitions install/update/uninstall hooks.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_schema().
|
||||
*/
|
||||
function job_scheduler_schema() {
|
||||
$schema = array();
|
||||
$schema['job_schedule'] = array(
|
||||
'description' => 'Schedule of jobs to be executed.',
|
||||
'fields' => array(
|
||||
'item_id' => array(
|
||||
'type' => 'serial',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'description' => 'Primary Key: Unique item ID.',
|
||||
),
|
||||
'name' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 128,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
'description' => 'Name of the schedule.',
|
||||
),
|
||||
'type' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 128,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
'description' => 'Type identifier of the job.',
|
||||
),
|
||||
'id' => array(
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'unsigned' => TRUE,
|
||||
'description' => 'Numeric identifier of the job.',
|
||||
),
|
||||
'period' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'default' => 0,
|
||||
'not null' => TRUE,
|
||||
'description' => 'Time period after which job is to be executed.',
|
||||
),
|
||||
'crontab' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
'description' => 'Crontab line in *NIX format.',
|
||||
),
|
||||
'data' => array(
|
||||
'type' => 'blob',
|
||||
'not null' => FALSE,
|
||||
'size' => 'big',
|
||||
'serialize' => TRUE,
|
||||
'description' => 'The arbitrary data for the item.',
|
||||
),
|
||||
'expire' => array(
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'description' => 'Timestamp when job expires.',
|
||||
),
|
||||
'created' => array(
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'description' => 'Timestamp when the item was created.',
|
||||
),
|
||||
'last' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'default' => 0,
|
||||
'not null' => TRUE,
|
||||
'description' => 'Timestamp when a job was last executed.',
|
||||
),
|
||||
'periodic' => array(
|
||||
'type' => 'int',
|
||||
'size' => 'small',
|
||||
'unsigned' => TRUE,
|
||||
'default' => 0,
|
||||
'not null' => TRUE,
|
||||
'description' => 'If true job will be automatically rescheduled.',
|
||||
),
|
||||
'next' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'default' => 0,
|
||||
'not null' => TRUE,
|
||||
'description' => 'Timestamp when a job is to be executed (next = last + period), used for fast ordering.',
|
||||
),
|
||||
'scheduled' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'default' => 0,
|
||||
'not null' => TRUE,
|
||||
'description' => 'Timestamp when a job was scheduled. 0 if a job is currently not scheduled.',
|
||||
),
|
||||
),
|
||||
'primary key' => array('item_id'),
|
||||
'indexes' => array(
|
||||
'name_type_id' => array('name', 'type', 'id'),
|
||||
'name_type' => array('name', 'type'),
|
||||
'next' => array('next'),
|
||||
'scheduled' => array('scheduled'),
|
||||
),
|
||||
);
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix indexes on next.
|
||||
*/
|
||||
function job_scheduler_update_6101() {
|
||||
$ret = array();
|
||||
db_drop_index($ret, 'job_schedule', 'last_period');
|
||||
db_drop_index($ret, 'job_schedule', 'periodic');
|
||||
db_add_index($ret, 'job_schedule', 'next', array('next'));
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename 'callback' to 'name' field.
|
||||
*/
|
||||
function job_scheduler_update_7100() {
|
||||
db_drop_index('job_schedule', 'callback_type_id');
|
||||
db_drop_index('job_schedule', 'callback_type');
|
||||
$spec = array(
|
||||
'type' => 'varchar',
|
||||
'length' => 128,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
'description' => 'Name of the schedule.',
|
||||
);
|
||||
db_change_field('job_schedule', 'callback', 'name', $spec);
|
||||
db_add_index('job_schedule', 'name_type_id', array('name', 'type', 'id'));
|
||||
db_add_index('job_schedule', 'name_type', array('name', 'type'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add fields: item_id, crontab, data, expire
|
||||
*/
|
||||
function job_scheduler_update_7101() {
|
||||
$spec = array(
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
'description' => 'Crontab line in *NIX format.',
|
||||
);
|
||||
db_add_field('job_schedule', 'crontab', $spec);
|
||||
$spec = array(
|
||||
'type' => 'blob',
|
||||
'not null' => FALSE,
|
||||
'size' => 'big',
|
||||
'serialize' => TRUE,
|
||||
'description' => 'The arbitrary data for the item.',
|
||||
);
|
||||
db_add_field('job_schedule', 'data', $spec);
|
||||
$spec = array(
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'description' => 'Timestamp when job expires.',
|
||||
);
|
||||
db_add_field('job_schedule', 'expire', $spec);
|
||||
$spec = array(
|
||||
'type' => 'serial',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'description' => 'Primary Key: Unique item ID.',
|
||||
);
|
||||
db_add_field('job_schedule', 'item_id', $spec, array('primary key' => array('item_id')));
|
||||
}
|
158
sites/all/modules/job_scheduler/job_scheduler.module
Normal file
158
sites/all/modules/job_scheduler/job_scheduler.module
Normal file
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* job scheduler module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Collects and returns scheduler info.
|
||||
*
|
||||
* @see hook_cron_job_scheduler_info()
|
||||
*
|
||||
* @param $name
|
||||
* Name of the schedule
|
||||
* @return array
|
||||
* Information for the schedule if $name, all the information if not
|
||||
*/
|
||||
function job_scheduler_info($name = NULL) {
|
||||
$info = &drupal_static(__FUNCTION__);
|
||||
if (!$info) {
|
||||
$info = module_invoke_all('cron_job_scheduler_info');
|
||||
drupal_alter('cron_job_scheduler_info', $info);
|
||||
}
|
||||
if ($name) {
|
||||
return isset($info[$name]) ? $info[$name] : NULL;
|
||||
}
|
||||
else {
|
||||
return $info;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_cron().
|
||||
*/
|
||||
function job_scheduler_cron() {
|
||||
// Reschedule all jobs if requested.
|
||||
if (variable_get('job_scheduler_rebuild_all', FALSE)) {
|
||||
foreach (job_scheduler_info() as $name => $info) {
|
||||
job_scheduler_rebuild_scheduler($name, $info);
|
||||
}
|
||||
variable_set('job_scheduler_rebuild_all', FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
// Reschedule stuck periodic jobs after one hour.
|
||||
db_update('job_schedule')
|
||||
->fields(array(
|
||||
'scheduled' => 0,
|
||||
))
|
||||
->condition('scheduled', REQUEST_TIME - 3600, '<')
|
||||
->condition('periodic', 1)
|
||||
->execute();
|
||||
|
||||
// Query and dispatch scheduled jobs.
|
||||
// Process a maximum of 200 jobs in a maximum of 30 seconds.
|
||||
$start = time();
|
||||
$total =
|
||||
$failed = 0;
|
||||
$jobs = db_select('job_schedule', NULL, array('fetch' => PDO::FETCH_ASSOC))
|
||||
->fields('job_schedule')
|
||||
->condition('scheduled', 0)
|
||||
->condition('next', REQUEST_TIME, '<=')
|
||||
->orderBy('next', 'ASC')
|
||||
->range(0, 200)
|
||||
->execute();
|
||||
foreach ($jobs as $job) {
|
||||
try {
|
||||
JobScheduler::get($job['name'])->dispatch($job);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
watchdog('job_scheduler', $e->getMessage(), array(), WATCHDOG_ERROR);
|
||||
$failed++;
|
||||
// Drop jobs that have caused exceptions
|
||||
JobScheduler::get($job['name'])->remove($job);
|
||||
}
|
||||
$total++;
|
||||
if (time() > ($start + 30)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Leave a note on how much time we spent processing.
|
||||
watchdog('job_scheduler', 'Finished processing scheduled jobs (!time s, !total total, !failed failed).', array('!time' => format_interval(time() - $start), '!total' => $total, '!failed' => $failed));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_modules_enabled().
|
||||
*/
|
||||
function job_scheduler_modules_enabled($modules) {
|
||||
job_scheduler_rebuild_all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_modules_disabled().
|
||||
*/
|
||||
function job_scheduler_modules_disabled($modules) {
|
||||
job_scheduler_rebuild_all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuild scheduled information after enable/disable modules
|
||||
*
|
||||
* @todo What should we do about missing ones when disabling their module?
|
||||
*/
|
||||
function job_scheduler_rebuild_all() {
|
||||
variable_set('job_scheduler_rebuild_all', TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuild a single scheduler
|
||||
*/
|
||||
function job_scheduler_rebuild_scheduler($name, $info = NULL) {
|
||||
$info = $info ? $info : job_scheduler_info($name);
|
||||
if (!empty($info['jobs'])) {
|
||||
$scheduler = JobScheduler::get($name);
|
||||
foreach ($info['jobs'] as $job) {
|
||||
if (!$scheduler->check($job)) {
|
||||
$scheduler->set($job);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_cron_queue_info().
|
||||
*
|
||||
* Provide queue worker information for jobs declared in
|
||||
* hook_cron_job_scheduler_info().
|
||||
*/
|
||||
function job_scheduler_cron_queue_info() {
|
||||
$queue = array();
|
||||
foreach (job_scheduler_info() as $name => $info) {
|
||||
if (!empty($info['jobs']) && !empty($info['queue name'])) {
|
||||
$queue[$info['queue name']] = array(
|
||||
'worker callback' => 'job_scheduler_cron_queue_worker',
|
||||
'time' => 60, // Some reasonable default as we don't know
|
||||
);
|
||||
}
|
||||
}
|
||||
return $queue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute job worker from queue
|
||||
*
|
||||
* Providing our own worker has the advantage that we can reschedule the job or take care of cleanup
|
||||
* Note that as we run the execute() action, the job won't be queued again this time.
|
||||
*/
|
||||
function job_scheduler_cron_queue_worker($job) {
|
||||
try {
|
||||
JobScheduler::get($job['name'])->execute($job);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
watchdog('job_scheduler', $e->getMessage(), array(), WATCHDOG_ERROR);
|
||||
// Drop jobs that have caused exceptions
|
||||
JobScheduler::get($job['name'])->remove($job);
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
Drupal Module: Job Scheduler Trigger
|
||||
====================================
|
||||
Extension for Job Scheduler to create timed periodic triggers.
|
||||
|
||||
This module provides a simple UI to configure trigger name and crontab. We provide no actions, though actions created
|
||||
by other modules can be set to be triggered with these timers.
|
||||
|
||||
Trigger type: job_scheduler
|
||||
Hook names will be created on the fly for configured triggers as: job_scheduler_1, job_scheduler_2, etc...
|
||||
|
||||
Jose A. Reyero, http://www.developmentseed.org
|
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Job Scheduler Trigger admin pages
|
||||
*/
|
||||
function job_scheduler_trigger_admin_overview() {
|
||||
$base_path = 'admin/config/system/job_scheduler';
|
||||
$destination = drupal_get_destination();
|
||||
$header = array(
|
||||
'title' => t('Title'),
|
||||
'crontab' => t('Cron tab'),
|
||||
'status' => t('Status'),
|
||||
'last' => t('Last'),
|
||||
'next' => t('Next'),
|
||||
'operations' => t('Operations'),
|
||||
);
|
||||
|
||||
$options = array();
|
||||
foreach (job_scheduler_trigger_list() as $trigger) {
|
||||
$next_time = job_scheduler_trigger_next_time($trigger->crontab);
|
||||
$options[$trigger->trid] = array(
|
||||
'title' => check_plain($trigger->title),
|
||||
'crontab' => check_plain($trigger->crontab),
|
||||
'status' => $trigger->status ? t('Enabled') : t('Disabled'),
|
||||
'last' => $trigger->last ? format_date($trigger->last) : t('Never'),
|
||||
'next' => $next_time ? format_date($next_time) : t('Never'),
|
||||
);
|
||||
$operations['edit'] = array(
|
||||
'title' => t('edit'),
|
||||
'href' => $base_path . '/' . $trigger->trid,
|
||||
'query' => $destination,
|
||||
);
|
||||
$options[$trigger->trid]['operations'] = array(
|
||||
'data' => array(
|
||||
'#theme' => 'links',
|
||||
'#links' => $operations,
|
||||
'#attributes' => array('class' => array('links', 'inline')),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
$form['triggers'] = array(
|
||||
'#theme' => 'table',
|
||||
'#header' => $header,
|
||||
'#rows' => $options,
|
||||
'#empty' => t('No triggers created yet.'),
|
||||
);
|
||||
|
||||
$form['add']['#markup'] = l(t('Add a new trigger'), $base_path . '/add', array('query' => $destination));
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Edit form for a trigger
|
||||
*/
|
||||
function job_scheduler_trigger_edit_form($form, &$form_state, $trigger) {
|
||||
if (!$trigger) {
|
||||
$trigger = (object)array('trid' => NULL, 'title' => t('New trigger'), 'crontab' => '* * * * *', 'status' => 0, 'last' => 0);
|
||||
}
|
||||
$form['trigger'] = array('#tree' => TRUE);
|
||||
$form['trigger']['trid'] = array('#type' => 'value', '#value' => $trigger->trid);
|
||||
$form['trigger']['title'] = array(
|
||||
'#title' => t('Title'),
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => $trigger->title,
|
||||
'#required' => TRUE,
|
||||
'#description' => t('This is the name of the trigger that will be created when enabled.'),
|
||||
);
|
||||
$form['trigger']['crontab'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Cron tab'),
|
||||
'#default_value' => $trigger->crontab,
|
||||
'#required' => TRUE,
|
||||
'#description' => t('Unix-style crontab line with: <i>minutes</i> <i>hours</i> <i>day-of-month</i> <i>month</i> <i>day-of-week</i>. Read <a href=@man-crontab>more about crontab</a>.', array('@man-crontab' => url('http://linux.die.net/man/5/crontab'))),
|
||||
);
|
||||
$form['trigger']['status'] = array(
|
||||
'#title' => t('Status'),
|
||||
'#type' => 'radios',
|
||||
'#options' => array(t('disabled'), t('enabled')),
|
||||
'#default_value' => $trigger->status,
|
||||
'#description' => t('When enabled, a trigger will be created with this crontab and jobs will be scheduled for it. Check everything is OK before enabling the trigger.'),
|
||||
);
|
||||
$form['trigger']['last'] = array(
|
||||
'#type' => 'item',
|
||||
'#title' => t('Last triggered'),
|
||||
'#markup' => format_date($trigger->last),
|
||||
);
|
||||
if ($trigger->trid && $trigger->crontab) {
|
||||
$next = job_scheduler_trigger_next_time($trigger->crontab);
|
||||
$form['trigger']['next'] = array(
|
||||
'#type' => 'item',
|
||||
'#title' => t('Next trigger'),
|
||||
'#markup' => $next ? format_date($next) : t('Never in the next year.'),
|
||||
);
|
||||
}
|
||||
$form['buttons']['update'] = array('#type' => 'submit', '#value' => t('Save'));
|
||||
|
||||
if ($trigger->trid) {
|
||||
$form['buttons']['delete'] = array('#type' => 'submit', '#value' => t('Delete'));
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate trigger
|
||||
*/
|
||||
function job_scheduler_trigger_edit_form_validate($form, &$form_state) {
|
||||
$trigger = $form_state['values']['trigger'];
|
||||
if ($trigger['crontab']) {
|
||||
if (!JobSchedulerCronTab::parse($trigger['crontab'])) {
|
||||
form_set_error('trigger][crontab', t('Invalid cron parameters.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit trigger
|
||||
*/
|
||||
function job_scheduler_trigger_edit_form_submit($form, &$form_state) {
|
||||
$op = isset($form_state['values']['op']) ? $form_state['values']['op'] : '';
|
||||
$trigger = $form_state['values']['trigger'];
|
||||
if ($op == t('Save')) {
|
||||
if (empty($trigger['trid'])) {
|
||||
// Create and then assign trigger name and create trigger
|
||||
drupal_write_record('job_scheduler_trigger', $trigger);
|
||||
$trigger['hook'] = 'job_scheduler_' . $trigger['trid'];
|
||||
drupal_write_record('job_scheduler_trigger', $trigger, 'trid');
|
||||
drupal_set_message(t('A new trigger has been created.'));
|
||||
}
|
||||
else {
|
||||
drupal_write_record('job_scheduler_trigger', $trigger, 'trid');
|
||||
drupal_set_message(t('The trigger has been updated.'));
|
||||
}
|
||||
}
|
||||
elseif ($op == t('Delete')) {
|
||||
db_delete('job_scheduler_trigger')
|
||||
->condition('trid', $trigger['trid'])
|
||||
->execute();
|
||||
drupal_set_message(t('The trigger has been deleted.'));
|
||||
// @todo Delete scheduled jobs
|
||||
}
|
||||
// Synchronize triggers, actions, scheduled jobs, etc..
|
||||
actions_synchronize();
|
||||
job_scheduler_rebuild_all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Quick calculate next time cron
|
||||
*/
|
||||
function job_scheduler_trigger_next_time($crontab) {
|
||||
$crontab = new JobSchedulerCronTab($crontab);
|
||||
return $crontab->cron ? $crontab->nextTime(REQUEST_TIME) : 0;
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
name = Job Scheduler Trigger
|
||||
description = Creates scheduler triggers that fire up at certain days, times
|
||||
core = 7.x
|
||||
php = 5.2
|
||||
dependencies[] = job_scheduler
|
||||
|
||||
; Information added by drupal.org packaging script on 2012-05-08
|
||||
version = "7.x-2.0-alpha3"
|
||||
core = "7.x"
|
||||
project = "job_scheduler"
|
||||
datestamp = "1336466457"
|
||||
|
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Implementation of hook_schema().
|
||||
*/
|
||||
function job_scheduler_trigger_schema() {
|
||||
$schema['job_scheduler_trigger'] = array(
|
||||
'description' => 'Schedule of triggers to be created.',
|
||||
'fields' => array(
|
||||
'trid' => array(
|
||||
'description' => 'Primary Key: unique trigger id.',
|
||||
'type' => 'serial',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
),
|
||||
'hook' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 32,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
'description' => 'Primary Key: The name of the internal Drupal hook; for example, job_scheduer_100.',
|
||||
),
|
||||
'title' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
'description' => 'Title for the trigger.',
|
||||
),
|
||||
'crontab' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
'description' => 'Crontab line in *NIX format.',
|
||||
),
|
||||
'status' => array(
|
||||
'description' => 'Boolean indicating whether the trigger is active.',
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 1,
|
||||
),
|
||||
'last' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'default' => 0,
|
||||
'not null' => TRUE,
|
||||
'description' => 'Timestamp when it was lat triggered.',
|
||||
),
|
||||
),
|
||||
'primary key' => array('trid'),
|
||||
);
|
||||
return $schema;
|
||||
}
|
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* job scheduler module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_help().
|
||||
*/
|
||||
function job_scheduler_trigger_help($path, $arg) {
|
||||
switch ($path) {
|
||||
case 'admin/structure/trigger/job_scheduler':
|
||||
// The first line is the very same text trigger module provides. Do not edit.
|
||||
$output = '<p>' . t('Triggers are events on your site, such as new content being added or a user logging in. The Trigger module associates these triggers with actions (functional tasks), such as unpublishing content containing certain keywords or e-mailing an administrator. The <a href="@url">Actions settings page</a> contains a list of existing actions and provides the ability to create and configure advanced actions (actions requiring configuration, such as an e-mail address or a list of banned words).', array('@url' => url('admin/config/system/actions'))) . '</p>';
|
||||
$output .= '<p>' . t('Below you can assign actions to run on a periodic basis. To create more triggers of this type use the <a href="@url">Job Scheduler configuration</a> page.', array('@url' => url('admin/config/system/job_scheduler'))) . '</p>';
|
||||
return $output;
|
||||
case 'admin/config/system/job_scheduler':
|
||||
$output = '<p>' . t('You can create any number of jobs that are triggered depending on a crontab.') . '</p>';
|
||||
$output .= '<p>' . t('To set actions for these triggers, go to the <a href="@url">Job Scheduler Triggers</a> page.', array('@url' => url('admin/structure/trigger/job_scheduler'))) . '</p>';
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_menu()
|
||||
*/
|
||||
function job_scheduler_trigger_menu() {
|
||||
$items['admin/config/system/job_scheduler'] = array(
|
||||
'title' => 'Trigger scheduler',
|
||||
'description' => 'Configure timely triggers',
|
||||
'page callback' => 'job_scheduler_trigger_admin_overview',
|
||||
'access arguments' => array('administer site configuration'),
|
||||
'file' => 'job_scheduler_trigger.admin.inc',
|
||||
);
|
||||
$items['admin/config/system/job_scheduler/add'] = array(
|
||||
'title' => 'Trigger scheduler',
|
||||
'description' => 'Configure timely triggers',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('job_scheduler_trigger_edit_form', NULL),
|
||||
'access arguments' => array('administer site configuration'),
|
||||
'file' => 'job_scheduler_trigger.admin.inc',
|
||||
);
|
||||
$items['admin/config/system/job_scheduler/%job_scheduler_trigger'] = array(
|
||||
'title' => 'Trigger scheduler',
|
||||
'description' => 'Configure timely triggers',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('job_scheduler_trigger_edit_form', 4),
|
||||
'access arguments' => array('administer site configuration'),
|
||||
'file' => 'job_scheduler_trigger.admin.inc',
|
||||
);
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_trigger_info().
|
||||
*/
|
||||
function job_scheduler_trigger_trigger_info() {
|
||||
$triggers = array();
|
||||
foreach (job_scheduler_trigger_list() as $trigger) {
|
||||
$label = $trigger->status ? $trigger->title : $trigger->title . ' ' . t('(Disabled)');
|
||||
$triggers['job_scheduler'][$trigger->hook] = array(
|
||||
'label' => $label,
|
||||
);
|
||||
}
|
||||
return $triggers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_job_scheduler_info()
|
||||
*/
|
||||
function job_scheduler_trigger_cron_job_scheduler_info() {
|
||||
foreach (job_scheduler_trigger_list() as $trigger) {
|
||||
if ($trigger->status) {
|
||||
$jobs[$trigger->trid] = array('id' => $trigger->trid, 'type' => $trigger->hook, 'crontab' => $trigger->crontab, 'periodic' => TRUE);
|
||||
}
|
||||
}
|
||||
if (!empty($jobs)) {
|
||||
$scheduler['job_scheduler_trigger'] = array(
|
||||
'worker callback' => 'job_scheduler_trigger_worker',
|
||||
'jobs' => $jobs,
|
||||
);
|
||||
return $scheduler;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get job list for job scheduler
|
||||
*/
|
||||
function job_scheduler_trigger_list() {
|
||||
return db_select('job_scheduler_trigger', 't')
|
||||
->fields('t')
|
||||
->orderBy('status', 'DESC')
|
||||
->execute()->fetchAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire up a scheduled trigger
|
||||
*/
|
||||
function job_scheduler_trigger_worker($job) {
|
||||
// Mark last time triggered for the records
|
||||
db_update('job_scheduler_trigger')
|
||||
->fields(array('last' => REQUEST_TIME))
|
||||
->condition('trid', $job['id'])
|
||||
->execute();
|
||||
if ($aids = trigger_get_assigned_actions($job['type'])) {
|
||||
$context = array(
|
||||
'group' => 'scheduler',
|
||||
'hook' => $job['type'],
|
||||
'job' => $job,
|
||||
);
|
||||
// Scheduler's object is the job from job_scheduler
|
||||
$object = (object)$job;
|
||||
actions_do(array_keys($aids), $object, $context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu loader
|
||||
*/
|
||||
function job_scheduler_trigger_load($trid) {
|
||||
return db_select('job_scheduler_trigger', 't')
|
||||
->fields('t')
|
||||
->condition('trid', $trid)
|
||||
->execute()->fetchObject();
|
||||
}
|
Reference in New Issue
Block a user