/** * Parse and execute the scheduled tasks in the specified file. * @param $file string */ function parseTasks($file) { $xmlParser = new XMLParser(); $tree = $xmlParser->parse($file); if (!$tree) { $xmlParser->destroy(); printf("Unable to parse file \"%s\"!\n", $file); exit(1); } foreach ($tree->getChildren() as $task) { $className = $task->getAttribute('class'); $frequency = $task->getChildByName('frequency'); if (isset($frequency)) { $canExecute = ScheduledTaskHelper::checkFrequency($className, $frequency); } else { // Always execute if no frequency is specified $canExecute = true; } if ($canExecute) { $this->executeTask($className, ScheduledTaskHelper::getTaskArgs($task)); } } $xmlParser->destroy(); }
/** * Check if a value is within the specified range. * @param $rangeStr string the range (e.g., 0, 1-5, *, etc.) * @param $currentValue int value to check if its in the range * @param $lastTimestamp int the last time the task was executed * @param $timeCompareStr string value to use in strtotime("-X $timeCompareStr") * @param $cutoffTimestamp int value will be considered valid if older than this * @return boolean */ function _isInRange($rangeStr, $currentValue, $lastTimestamp, $timeCompareStr, $cutoffTimestamp) { $isValid = false; $rangeArray = explode(',', $rangeStr); if ($cutoffTimestamp > $lastTimestamp) { // Execute immediately if the cutoff time period has past since the task was last run $isValid = true; } for ($i = 0, $count = count($rangeArray); !$isValid && $i < $count; $i++) { if ($rangeArray[$i] == '*') { // Is wildcard $isValid = true; } if (is_numeric($rangeArray[$i])) { // Is just a value $isValid = $currentValue == (int) $rangeArray[$i]; } else { if (preg_match('/^(\\d*)\\-(\\d*)$/', $rangeArray[$i], $matches)) { // Is a range $isValid = ScheduledTaskHelper::_isInNumericRange($currentValue, (int) $matches[1], (int) $matches[2]); } else { if (preg_match('/^(.+)\\/(\\d+)$/', $rangeArray[$i], $matches)) { // Is a range with a skip factor $skipRangeStr = $matches[1]; $skipFactor = (int) $matches[2]; if ($skipRangeStr == '*') { $isValid = true; } else { if (preg_match('/^(\\d*)\\-(\\d*)$/', $skipRangeStr, $matches)) { $isValid = ScheduledTaskHelper::_isInNumericRange($currentValue, (int) $matches[1], (int) $matches[2]); } } if ($isValid) { // Check against skip factor $isValid = strtotime("-{$skipFactor} {$timeCompareStr}") > $lastTimestamp; } } } } } return $isValid; }
/** * Get all scheduled tasks that needs to be executed. * @return array */ function _getTasksToRun() { $tasksToRun = array(); $isEnabled = $this->getSetting(0, 'enabled'); if ($isEnabled) { $taskDao =& DAORegistry::getDao('ScheduledTaskDAO'); // Grab the scheduled scheduled tree $scheduledTasks = $this->getSetting(0, 'crontab'); if (is_null($scheduledTasks)) { $this->_parseCrontab(); $scheduledTasks = $this->getSetting(0, 'crontab'); } foreach ($scheduledTasks as $task) { // We don't allow tasks without frequency, see _parseCronTab(). $frequency = new XMLNode(); $frequency->setAttribute(key($task['frequency']), current($task['frequency'])); $canExecute = ScheduledTaskHelper::checkFrequency($task['className'], $frequency); if ($canExecute) { $tasksToRun[] = $task; } } } return $tasksToRun; }
/** * Clear scheduled tasks execution logs. */ function clearScheduledTaskLogFiles() { $this->validate(); import('lib.pkp.classes.scheduledTask.ScheduledTaskHelper'); ScheduledTaskHelper::clearExecutionLogs(); Request::redirect(null, 'admin'); }
/** * Parse all scheduled tasks files and * save the result object in database. */ function _parseCrontab() { $xmlParser = new XMLParser(); $taskFilesPath = array(); // Let plugins register their scheduled tasks too. HookRegistry::call('AcronPlugin::parseCronTab', array(&$taskFilesPath)); // Reference needed. // Add the default tasks file. $taskFilesPath[] = Config::getVar('general', 'registry_dir') . '/scheduledTasks.xml'; // TODO: make this a plugin setting, rather than assuming. $tasks = array(); foreach ($taskFilesPath as $filePath) { $tree = $xmlParser->parse($filePath); if (!$tree) { $xmlParser->destroy(); // TODO: graceful error handling fatalError('Error parsing scheduled tasks XML file: ' . $filePath); } foreach ($tree->getChildren() as $task) { $frequency = $task->getChildByName('frequency'); $args = ScheduledTaskHelper::getTaskArgs($task); // Tasks without a frequency defined, or defined to zero, will run on every request. // To avoid that happening (may cause performance problems) we // setup a default period of time. $frequencyAttributes = $frequency->getAttributes(); $setDefaultFrequency = true; $minHoursRunPeriod = 24; if (is_array($frequencyAttributes)) { foreach ($frequencyAttributes as $key => $value) { if ($value != 0) { $setDefaultFrequency = false; break; } } } $tasks[] = array('className' => $task->getAttribute('class'), 'frequency' => $setDefaultFrequency ? array('hour' => $minHoursRunPeriod) : $frequencyAttributes, 'args' => $args); } $xmlParser->destroy(); } // Store the object. $this->updateSetting(0, 'crontab', $tasks, 'object'); }