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}");
152 $this->events->triggerResults(
'cron', $interval, [
153 'time' =>
$time->getTimestamp(),
155 'logger' => $cron_logger,
157 EventsService::OPTION_BEGIN_CALLBACK => $begin_callback,
158 EventsService::OPTION_END_CALLBACK => $end_callback,
160 }
catch (\Throwable $t) {
166 $complete = $this->translator->translate(
'admin:cron:complete', [$interval, $now->format(DATE_RFC2822)]);
167 $cron_logger->notice($complete);
169 if (file_exists($filename) && is_readable($filename)) {
170 return file_get_contents($filename);
189 $this->events->triggerAfter(
'cron', $interval,
new \
DateTime());
190 }
catch (\Throwable $t) {
194 $cron_logger->close();
195 $this->rotateLogs($interval);
196 $this->logCompletion($interval);
209 public function getLogs(
string $interval,
bool $filenames_only =
false): array {
210 $fh = new \ElggFile();
212 $fh->setFilename(
"cron/{$interval}/dummy.log");
214 $dir = pathinfo($fh->getFilenameOnFilestore(), PATHINFO_DIRNAME);
215 if (!is_dir($dir) || !is_readable($dir)) {
219 $dh = new \DirectoryIterator($dir);
222 foreach ($dh as $file) {
223 if ($file->isDot() || !$file->isFile()) {
227 if ($filenames_only) {
228 $files[] = $file->getFilename();
230 $files[$file->getFilename()] = file_get_contents($file->getPathname());
234 if ($filenames_only) {
237 uksort($files,
'strnatcasecmp');
240 return array_reverse($files);
251 $fh = new \ElggFile();
253 $fh->setFilename(
"cron/{$interval}.complete");
255 if (!$fh->exists()) {
259 $date = $fh->grabFile();
266 return Values::normalizeTime($date);
283 $result = $this->events->triggerResults(
'cron:intervals',
'system', [], $this->default_intervals);
285 $this->
getLogger()->warning(
"The event 'cron:intervals', 'system' should return an array, " . gettype(
$result) .
' given');
287 $result = $this->default_intervals;
310 $date =
$time->format(\DateTimeInterface::ATOM);
312 $date = preg_replace(
'/[^a-zA-Z0-9_-]+/',
'-', $date);
314 $fh = new \ElggFile();
316 $fh->setFilename(
"cron/{$interval}/{$date}.log");
318 return $fh->getFilenameOnFilestore();
329 $files = $this->getLogs($interval,
true);
330 if (
count($files) <= self::LOG_FILES_TO_KEEP) {
334 $fh = new \ElggFile();
337 while (
count($files) > self::LOG_FILES_TO_KEEP) {
340 $fh->setFilename(
"cron/{$interval}/{$filename}");
353 $fh = new \ElggFile();
355 $fh->setFilename(
"cron/{$interval}.complete");
358 if ($fh->open(
'write') ===
false) {
367 $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.
Extension of the DateTime class to support formatting a date using the locale.
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.