/** * Looks if an execution of a given cronjob is pending. * * The basic principle of the wcf cronjobs is that a call to this method is being triggered * via ajax with every Burning Board page view. This is being done in order to ensure a sufficient * accuracy of execution time, despite the lack of a "real" crond. * Every time this method is being called, configured execution times for a given cronjob * may most likely either lie ahead, or be a thing of the past. In the latter case this cronjob * is being estimated as "pending" and thus be executed. */ protected function findPendingCronjobs() { // there might be ranges of date/time values specified. Ranges can be expressed // either with a comma-separated list, or with a dash, or with a combination of both. // also there are intervals possible, expressed with an asterisk followed by a slash // and a number (e.g. '*/2' meaning 'every two somethings'). days of week and months // may also be noted as abbreviations of plaintext names. foreach ($this->cronjobsCache as $key => $cronjobsCache) { $this->plannedExecs = array(); if (intval($cronjobsCache['execMultiple']) == 1) { // set identificator for an eventual execMultiple action. $this->execMultiple = 1; // reset counter needed for an eventual execMultiple action. $this->countMultipleExecs = 0; // initiate array where "planned" dates of inbetween execs are being stored if execMultiple is set. if (intval($cronjobsCache['nextExec']) > 1) { $this->plannedExecs[] = intval($cronjobsCache['nextExec']); } } else { $this->execMultiple = 0; $this->countMultipleExecs = 1; } // don't execute this cronjob in case nextExec is in the future. if ($cronjobsCache['nextExec'] > $this->now) { unset($this->cronjobsCache[$key]); continue; } // determine time base. if ($this->execMultiple == 0) { $this->timebase = $this->now; } else { if ($this->execMultiple == 1) { if (intval($cronjobsCache['nextExec'] <= 1)) { $this->timebase = $this->now; $this->countMultipleExecs = 1; } else { $this->timebase = $cronjobsCache['nextExec']; // the nextExec determined during last execution. } } } // get the actual nextExec time. if ($this->findCronjobNextExec($cronjobsCache) === false) { unset($this->cronjobsCache[$key]); continue; } // write new lastExec and nextExec timestamps to database and add log entry. $cronjobObj = new CronjobEditor(null, $cronjobsCache); $cronjobObj->setNextExec($this->nextExec); $this->cronjobsCache[$key]['newLogID'] = $cronjobObj->logExec(); } // now clear the cache. WCF::getCache()->clear(WCF_DIR . 'cache', 'cache.cronjobs-*.php'); // memcache workaround to be sure that at least the cache of the active application is cleared WCF::getCache()->clearResource($this->cacheName); foreach ($this->cronjobsCache as $cronjobsCache) { try { // now really execute the cronjob. $this->execPendingCronjobs($cronjobsCache); } catch (SystemException $e) { CronjobEditor::logSuccess($cronjobsCache['newLogID'], false, $e); continue; } } }
/** * Executes this cronjob. */ public function execute() { // create log entry $logID = CronjobEditor::logExec(); // include class file $classPath = FileUtil::getRealPath(WCF_DIR . $this->packageDir . $this->classPath); if (!file_exists($classPath)) { throw new SystemException("unable to find class file '" . $classPath . "'", 11000); } require_once $classPath; // create instance. $className = StringUtil::getClassName($this->classPath); if (!class_exists($className)) { throw new SystemException("unable to find class '" . $className . "'", 11001); } // execute cronjob. $cronjobExec = new $className(); if (method_exists($cronjobExec, 'execute')) { $cronjobExec->execute($this->data); } // log success. CronjobEditor::logSuccess($logID, true); }