23 protected const LOG_FILES_TO_KEEP = 5;
25 protected array $default_intervals = [
26 'minute' =>
'* * * * *',
27 'fiveminute' =>
'*/5 * * * *',
28 'fifteenmin' =>
'*/15 * * * *',
29 'halfhour' =>
'*/30 * * * *',
30 'hourly' =>
'0 * * * *',
31 'daily' =>
'0 0 * * *',
32 'weekly' =>
'0 0 * * 0',
33 'monthly' =>
'0 0 1 * *',
34 'yearly' =>
'0 0 1 1 *',
55 public function run(array $intervals = null,
bool $force =
false): array {
56 if (!isset($intervals)) {
57 $intervals = array_keys($this->default_intervals);
60 $allowed_intervals = $this->getConfiguredIntervals();
62 $scheduler =
new Scheduler();
65 foreach ($intervals as $interval) {
66 if (!array_key_exists($interval, $allowed_intervals)) {
67 throw new CronException(
"{$interval} is not a recognized cron interval. Please use one of the following: " .
implode(
', ', array_keys($allowed_intervals)));
70 $cron_interval = $force ? $allowed_intervals[
'minute'] : $allowed_intervals[$interval];
73 $cron_logger = \Elgg\Logger\Cron::factory([
74 'interval' => $interval,
79 ->call(
function () use ($interval,
$time, $cron_logger,
$filename) {
83 ->before(
function () use ($interval,
$time, $cron_logger) {
84 $this->before($interval, $cron_logger,
$time);
86 ->then(
function (
$output) use ($interval, $cron_logger) {
87 $this->after(
$output, $interval, $cron_logger);
91 return $scheduler->run(
$time);
109 $this->events->triggerBefore(
'cron', $interval,
$time);
110 }
catch (\Throwable $t) {
115 set_time_limit((
int) ini_get(
'max_execution_time'));
119 $cron_logger->notice($this->translator->translate(
'admin:cron:started', [$interval,
$time->format(DATE_RFC2822)]));
120 $cron_logger->notice($this->translator->translate(
'admin:cron:started:actual', [$interval, $now->format(DATE_RFC2822)]));
139 $begin_callback =
function (array
$params) use ($cron_logger) {
142 $cron_logger->notice(
"Starting {$readable_callable}");
145 $end_callback =
function (array
$params) use ($cron_logger) {
148 $cron_logger->notice(
"Finished {$readable_callable}");
151 $this->events->trigger(
'cron', $interval, [
152 'time' =>
$time->getTimestamp(),
154 'logger' => $cron_logger,
156 EventsService::OPTION_BEGIN_CALLBACK => $begin_callback,
157 EventsService::OPTION_END_CALLBACK => $end_callback,
159 }
catch (\Throwable $t) {
165 $complete = $this->translator->translate(
'admin:cron:complete', [$interval, $now->format(DATE_RFC2822)]);
166 $cron_logger->notice($complete);
168 if (file_exists($filename) && is_readable($filename)) {
169 return file_get_contents($filename);
188 $this->events->triggerAfter(
'cron', $interval,
new \
DateTime());
189 }
catch (\Throwable $t) {
193 $cron_logger->close();
194 $this->rotateLogs($interval);
195 $this->logCompletion($interval);
208 public function getLogs(
string $interval,
bool $filenames_only =
false): array {
209 $fh = new \ElggFile();
211 $fh->setFilename(
"cron/{$interval}/dummy.log");
213 $dir = pathinfo($fh->getFilenameOnFilestore(), PATHINFO_DIRNAME);
214 if (!is_dir($dir) || !is_readable($dir)) {
218 $dh = new \DirectoryIterator($dir);
221 foreach ($dh as $file) {
222 if ($file->isDot() || !$file->isFile()) {
226 if ($filenames_only) {
227 $files[] = $file->getFilename();
229 $files[$file->getFilename()] = file_get_contents($file->getPathname());
233 if ($filenames_only) {
236 uksort($files,
'strnatcasecmp');
239 return array_reverse($files);
250 $fh = new \ElggFile();
252 $fh->setFilename(
"cron/{$interval}.complete");
254 if (!$fh->exists()) {
258 $date = $fh->grabFile();
265 return Values::normalizeTime($date);
282 $result = $this->events->triggerResults(
'cron:intervals',
'system', [], $this->default_intervals);
284 $this->
getLogger()->warning(
"The event 'cron:intervals', 'system' should return an array, " . gettype(
$result) .
' given');
286 $result = $this->default_intervals;
309 $date =
$time->format(\DateTimeInterface::ATOM);
311 $date = preg_replace(
'/[^a-zA-Z0-9_-]+/',
'-', $date);
313 $fh = new \ElggFile();
315 $fh->setFilename(
"cron/{$interval}/{$date}.log");
317 return $fh->getFilenameOnFilestore();
328 $files = $this->getLogs($interval,
true);
329 if (
count($files) <= self::LOG_FILES_TO_KEEP) {
333 $fh = new \ElggFile();
336 while (
count($files) > self::LOG_FILES_TO_KEEP) {
339 $fh->setFilename(
"cron/{$interval}/{$filename}");
352 $fh = new \ElggFile();
354 $fh->setFilename(
"cron/{$interval}.complete");
357 if ($fh->open(
'write') ===
false) {
366 $fh->write($now->format(\DateTimeInterface::ATOM));
$params
Saves global plugin settings.
array __construct(protected EventsService $events, protected Translator $translator)
Constructor.
getConfiguredIntervals(bool $only_names=false)
Get the cron interval configuration.
c Accompany it with the information you received as to the offer to distribute corresponding source complete source code means all the source code for all modules it plus any associated interface definition plus the scripts used to control compilation and installation of the executable as a special the source code distributed need not include anything that is normally and so on of the operating system on which the executable unless that component itself accompanies the executable If distribution of executable or object code is made by offering access to copy from a designated then offering equivalent access to copy the source code from the same place counts as distribution of the source even though third parties are not compelled to copy the source along with the object code You may not or distribute the Program except as expressly provided under this License Any attempt otherwise to sublicense or distribute the Program is void
if(!$annotation instanceof ElggAnnotation) $time
trait TimeUsing
Adds methods for setting the current time (for testing)
Generic interface which allows catching of all exceptions thrown in Elgg.
getLastCompletion(string $interval)
Get the time of the last completion of a cron interval.
before(string $interval,\Elgg\Logger\Cron $cron_logger,\DateTime $time=null)
Execute commands before cron interval is run.
elgg_extract($key, $array, $default=null, bool $strict=true)
Checks for $array[$key] and returns its value if it exists, else returns $default.
getLogFilename(string $interval,\DateTime $time=null)
Get a filename to log in.
getCurrentTime($modifier= '')
Get the (cloned) time.
rotateLogs(string $interval)
Rotate the log files.
trait Loggable
Enables adding a logger.
getLogs(string $interval, bool $filenames_only=false)
Get the log files for a given cron interval.
logCompletion(string $interval)
Log the completion time of a cron interval.
after(string $output, string $interval,\Elgg\Logger\Cron $cron_logger)
Printers handler result.
elgg_get_site_entity()
Get the current site entity.
getLogger()
Returns logger.
execute(string $interval,\Elgg\Logger\Cron $cron_logger, string $filename,\DateTime $time=null)
Execute handlers attached to a specific cron interval.
A generic parent class for cron exceptions.
run(array $intervals=null, bool $force=false)
Executes handlers for periods that have elapsed since last cron.