ILIAS  release_5-2 Revision v5.2.25-18-g3f80b828510
class.ilCronManager.php
Go to the documentation of this file.
1<?php
2
3/* Copyright (c) 1998-2010 ILIAS open source, Extended GPL, see docs/LICENSE */
4
12{
16 public static function runActiveJobs()
17 {
18 global $ilLog, $ilSetting;
19
20 // separate log for cron
21 // $this->log->setFilename($_COOKIE["ilClientId"]."_cron.txt");
22
23 $ilLog->write("CRON - batch start");
24
25 $ilSetting->set("last_cronjob_start_ts", time());
26
27 // ilLink::_getStaticLink() should work in crons
28 if(!defined("ILIAS_HTTP_PATH"))
29 {
30 define("ILIAS_HTTP_PATH", ilUtil::_getHttpPath());
31 }
32
33 // system
34 foreach(self::getCronJobData(null, false) as $row)
35 {
36 $job = self::getJobInstanceById($row["job_id"]);
37 if($job)
38 {
39 // #18411 - we are NOT using the initial job data as it might be outdated at this point
40 self::runJob($job);
41 }
42 }
43
44 // plugins
45 foreach(self::getPluginJobs(true) as $item)
46 {
47 self::runJob($item[0], $item[1]);
48 }
49
50 $ilLog->write("CRON - batch end");
51 }
52
59 public static function runJobManual($a_job_id)
60 {
61 global $ilLog;
62
63 $result = false;
64
65 $ilLog->write("CRON - manual start (".$a_job_id.")");
66
67 $job = self::getJobInstanceById($a_job_id);
68 if($job)
69 {
70 if($job->isManuallyExecutable())
71 {
72 $result = self::runJob($job, null, true);
73 }
74 else
75 {
76 $ilLog->write("CRON - job ".$a_job_id." is not intended to be executed manually");
77 }
78 }
79 else
80 {
81 $ilLog->write("CRON - job ".$a_job_id." seems invalid or is inactive");
82 }
83
84 $ilLog->write("CRON - manual end (".$a_job_id.")");
85
86 return $result;
87 }
88
97 protected static function runJob(ilCronJob $a_job, array $a_job_data = null, $a_manual = false)
98 {
99 global $ilLog, $ilDB;
100
101 $did_run = false;
102
103 include_once "Services/Cron/classes/class.ilCronJobResult.php";
104
105 if($a_job_data === null)
106 {
107 // aquire "fresh" job (status) data
108 $a_job_data = array_pop(self::getCronJobData($a_job->getId()));
109 }
110
111 // already running?
112 if($a_job_data["alive_ts"])
113 {
114 $ilLog->write("CRON - job ".$a_job_data["job_id"]." still running");
115
116 $cut = 60*60*3; // 3h
117
118 // is running (and has not pinged) for 3 hours straight, we assume it crashed
119 if(time()-$a_job_data["alive_ts"] > $cut)
120 {
121 $ilDB->manipulate("UPDATE cron_job SET".
122 " running_ts = ".$ilDB->quote(0, "integer").
123 " , alive_ts = ".$ilDB->quote(0, "integer").
124 " WHERE job_id = ".$ilDB->quote($a_job_data["job_id"], "text"));
125
126 self::deactivateJob($a_job); // #13082
127
128 $result = new ilCronJobResult();
131 $result->setMessage("Cron job deactivated because it has been inactive for 3 hours");
132
133 if(!$a_manual)
134 {
136 }
137
138 self::updateJobResult($a_job, $result, $a_manual);
139
140 $ilLog->write("CRON - job ".$a_job_data["job_id"]." deactivated (assumed crash)");
141 }
142 }
143 // initiate run?
144 else if($a_job->isActive($a_job_data["job_result_ts"],
145 $a_job_data["schedule_type"], $a_job_data["schedule_value"], $a_manual))
146 {
147 $ilLog->write("CRON - job ".$a_job_data["job_id"]." started");
148
149 $ilDB->manipulate("UPDATE cron_job SET".
150 " running_ts = ".$ilDB->quote(time(), "integer").
151 " , alive_ts = ".$ilDB->quote(time(), "integer").
152 " WHERE job_id = ".$ilDB->quote($a_job_data["job_id"], "text"));
153
154 $ts_in = self::getMicrotime();
155 $result = $a_job->run();
156 $ts_dur = self::getMicrotime()-$ts_in;
157
158 // no proper result
159 if(!$result instanceof ilCronJobResult)
160 {
161 $result = new ilCronJobResult();
164 $result->setMessage("Cron job did not return a proper result");
165
166 if(!$a_manual)
167 {
169 }
170
171 $ilLog->write("CRON - job ".$a_job_data["job_id"]." no result");
172 }
173 // no valid configuration, job won't work
175 {
176 self::deactivateJob($a_job);
177
178 if(!$a_manual)
179 {
181 }
182
183 $ilLog->write("CRON - job ".$a_job_data["job_id"]." invalid configuration");
184 }
185 // success!
186 else
187 {
188 $did_run = true;
189 }
190
191 $result->setDuration($ts_dur);
192
193 self::updateJobResult($a_job, $result, $a_manual);
194
195 $ilDB->manipulate("UPDATE cron_job SET".
196 " running_ts = ".$ilDB->quote(0, "integer").
197 " , alive_ts = ".$ilDB->quote(0, "integer").
198 " WHERE job_id = ".$ilDB->quote($a_job_data["job_id"], "text"));
199
200 $ilLog->write("CRON - job ".$a_job_data["job_id"]." finished");
201 }
202 else
203 {
204 $ilLog->write("CRON - job ".$a_job_data["job_id"]." returned status inactive");
205 }
206
207 return $did_run;
208 }
209
216 public static function getJobInstanceById($a_job_id)
217 {
218 global $ilLog, $ilPluginAdmin;
219
220 // plugin
221 if(substr($a_job_id, 0, 4) == "pl__")
222 {
223 $parts = explode("__", $a_job_id);
224 $pl_name = $parts[1];
225 $job_id = $parts[2];
226 if($ilPluginAdmin->isActive(IL_COMP_SERVICE, "Cron", "crnhk", $pl_name))
227 {
228 $plugin_obj = $ilPluginAdmin->getPluginObject(IL_COMP_SERVICE,
229 "Cron", "crnhk", $pl_name);
230 $job = $plugin_obj->getCronJobInstance($job_id);
231 if($job instanceof ilCronJob)
232 {
233 // should never happen but who knows...
234 if(!sizeof(ilCronManager::getCronJobData($job_id)))
235 {
236 // as job is not "imported" from xml
238 }
239 return $job;
240 }
241 }
242
243 return null;
244 }
245 // system
246 else
247 {
248 $job_data = array_pop(self::getCronJobData($a_job_id));
249 if($job_data["job_id"] == $a_job_id)
250 {
251 return self::getJobInstance($job_data["job_id"], $job_data["component"],
252 $job_data["class"], $job_data["path"]);
253 }
254 }
255
256 $ilLog->write("CRON - job ".$a_job_id." seems invalid or is inactive");
257 }
258
267 public static function getJobInstance($a_id, $a_component, $a_class, $a_path = null)
268 {
269 global $ilLog;
270
271 if(!$a_path)
272 {
273 $a_path = $a_component."/classes/";
274 }
275 $class_file = $a_path."class.".$a_class.".php";
276 if(file_exists($class_file))
277 {
278 include_once $class_file;
279 if(class_exists($a_class))
280 {
281 $job = new $a_class();
282 if($job instanceof ilCronJob)
283 {
284 if($job->getId() == $a_id)
285 {
286 return $job;
287 }
288 else
289 {
290 $mess .= " - job id mismatch";
291 }
292 }
293 else
294 {
295 $mess .= " - does not extend ilCronJob";
296 }
297 }
298 else
299 {
300 $mess = "- class not found in file";
301 }
302 }
303 else
304 {
305 $mess = " - class file not found";
306 }
307
308 $ilLog->write("Cron XML - Job ".$a_id." in class ".$a_class." (".
309 $class_file.") is invalid.".$mess);
310 }
311
318 protected static function sendNotification(ilCronJob $a_job, $a_message)
319 {
320 // :TODO:
321 }
322
323 public static function createDefaultEntry(ilCronJob $a_job, $a_component, $a_class, $a_path)
324 {
325 global $ilDB, $ilLog, $ilSetting;
326
327 // already exists?
328 $sql = "SELECT job_id, schedule_type FROM cron_job".
329 " WHERE component = ".$ilDB->quote($a_component, "text").
330 " AND job_id = ".$ilDB->quote($a_job->getId(), "text");
331 $set = $ilDB->query($sql);
332 $row = $ilDB->fetchAssoc($set);
333 $job_exists = ($row["job_id"] == $a_job->getId());
334 $schedule_type = $row["schedule_type"];
335
336 // new job
337 if(!$job_exists)
338 {
339 $sql = "INSERT INTO cron_job (job_id, component, class, path)".
340 " VALUES (".$ilDB->quote($a_job->getId(), "text").", ".
341 $ilDB->quote($a_component, "text").", ".
342 $ilDB->quote($a_class, "text").", ".
343 $ilDB->quote($a_path, "text").")";
344 $ilDB->manipulate($sql);
345
346 $ilLog->write("Cron XML - Job ".$a_job->getId()." in class ".$a_class.
347 " added.");
348
349 // only if flexible
351 $a_job->getDefaultScheduleType(),
352 $a_job->getDefaultScheduleValue());
353
354 // #12221
355 if(!is_object($ilSetting))
356 {
357 include_once "Services/Administration/classes/class.ilSetting.php";
358 $ilSetting = new ilSetting();
359 }
360
361 if($a_job->hasAutoActivation())
362 {
363 self::activateJob($a_job);
364 }
365 else
366 {
367 // to overwrite dependent settings
368 $a_job->activationWasToggled(false);
369 }
370 }
371 // existing job - but schedule is flexible now
372 else if($a_job->hasFlexibleSchedule() && !$schedule_type)
373 {
375 $a_job->getDefaultScheduleType(),
376 $a_job->getDefaultScheduleValue());
377 }
378 // existing job - but schedule is static now
379 else if(!$a_job->hasFlexibleSchedule() && $schedule_type)
380 {
381 self::updateJobSchedule($a_job, null, null);
382 }
383 }
384
393 public static function updateFromXML($a_component, $a_id, $a_class, $a_path = null)
394 {
395 global $ilDB;
396
397 if(!$ilDB->tableExists("cron_job"))
398 {
399 return;
400 }
401
402 // only if job seems valid
403 $job = self::getJobInstance($a_id, $a_component, $a_class, $a_path);
404 if($job)
405 {
406 self::createDefaultEntry($job, $a_component, $a_class, $a_path);
407 }
408 }
409
416 public static function clearFromXML($a_component, array $a_xml_job_ids)
417 {
418 global $ilDB, $ilLog;
419
420 if(!$ilDB->tableExists("cron_job"))
421 {
422 return;
423 }
424
425 // gather existing jobs
426 $all_jobs = array();
427 $sql = "SELECT job_id FROM cron_job".
428 " WHERE component = ".$ilDB->quote($a_component, "text");
429 $set = $ilDB->query($sql);
430 while($row = $ilDB->fetchAssoc($set))
431 {
432 $all_jobs[] = $row["job_id"];
433 }
434
435 if(sizeof($all_jobs))
436 {
437 if(sizeof($a_xml_job_ids))
438 {
439 // delete obsolete job data
440 foreach($all_jobs as $job_id)
441 {
442 if(!in_array($job_id, $a_xml_job_ids))
443 {
444 $ilDB->manipulate("DELETE FROM cron_job".
445 " WHERE component = ".$ilDB->quote($a_component, "text").
446 " AND job_id = ".$ilDB->quote($job_id, "text"));
447
448 $ilLog->write("Cron XML - Job ".$job_id." in class ".$a_component.
449 " deleted.");
450 }
451 }
452 }
453 else
454 {
455 $ilDB->manipulate("DELETE FROM cron_job".
456 " WHERE component = ".$ilDB->quote($a_component, "text"));
457
458 $ilLog->write("Cron XML - All jobs deleted for ".$a_component." as component is inactive.");
459 }
460 }
461 }
462
463 public static function getPluginJobs($a_only_active = false)
464 {
465 global $ilPluginAdmin;
466
467 $res = array();
468
469 foreach($ilPluginAdmin->getActivePluginsForSlot(IL_COMP_SERVICE, "Cron", "crnhk") as $pl_name)
470 {
471 $plugin_obj = $ilPluginAdmin->getPluginObject(IL_COMP_SERVICE, "Cron", "crnhk", $pl_name);
472
473 foreach((array)$plugin_obj->getCronJobInstances() as $job)
474 {
475 $item = array_pop(ilCronManager::getCronJobData($job->getId()));
476 if(!sizeof($item))
477 {
478 // as job is not "imported" from xml
480 }
481
482 $item = array_pop(ilCronManager::getCronJobData($job->getId()));
483
484 // #17941
485 if(!$a_only_active ||
486 $item["job_status"] == 1)
487 {
488 $res[$job->getId()] = array($job, $item);
489 }
490 }
491 }
492
493 return $res;
494 }
495
503 public static function getCronJobData($a_id = null, $a_include_inactive = true)
504 {
505 global $ilDB;
506
507 $res = array();
508
509 if($a_id && !is_array($a_id))
510 {
511 $a_id = array($a_id);
512 }
513
514 $sql = "SELECT * FROM cron_job";
515
516 $where = array();
517 if($a_id)
518 {
519 $where[] = $ilDB->in("job_id", $a_id, "", "text");
520 }
521 else
522 {
523 $where[] = "class <> ".$ilDB->quote(IL_COMP_PLUGIN, "text");
524 }
525 if(!$a_include_inactive)
526 {
527 $where[] = "job_status = ".$ilDB->quote(1, "integer");
528 }
529 if(sizeof($where))
530 {
531 $sql .= " WHERE ".implode(" AND ", $where);
532 }
533
534 // :TODO: discuss job execution order
535 $sql .= " ORDER BY job_id";
536
537 $set = $ilDB->query($sql);
538 while($row = $ilDB->fetchAssoc($set))
539 {
540 $res[] = $row;
541 }
542
543 return $res;
544 }
545
551 public static function resetJob(ilCronJob $a_job)
552 {
553 global $ilDB;
554
555 include_once "Services/Cron/classes/class.ilCronJobResult.php";
556 $result = new ilCronJobResult();
559 $result->setMessage("Cron job re-activated by admin");
560 self::updateJobResult($a_job, $result, true);
561
562 $ilDB->manipulate("UPDATE cron_job".
563 " SET running_ts = ".$ilDB->quote(0, "integer").
564 " , alive_ts = ".$ilDB->quote(0, "integer").
565 " , job_result_ts = ".$ilDB->quote(0, "integer").
566 " WHERE job_id = ".$ilDB->quote($a_job->getId(), "text"));
567
568 self::activateJob($a_job, true);
569 }
570
577 public static function activateJob(ilCronJob $a_job, $a_manual = false)
578 {
579 global $ilDB, $ilUser;
580
581 $user_id = $a_manual ? $ilUser->getId() : 0;
582
583 $sql = "UPDATE cron_job SET ".
584 " job_status = ".$ilDB->quote(1, "integer").
585 " , job_status_user_id = ".$ilDB->quote($user_id, "integer").
586 " , job_status_type = ".$ilDB->quote($a_manual, "integer").
587 " , job_status_ts = ".$ilDB->quote(time(), "integer").
588 " WHERE job_id = ".$ilDB->quote($a_job->getId(), "text");
589 $ilDB->manipulate($sql);
590
591 $a_job->activationWasToggled(true);
592 }
593
600 public static function deactivateJob(ilCronJob $a_job, $a_manual = false)
601 {
602 global $ilDB, $ilUser;
603
604 $user_id = $a_manual ? $ilUser->getId() : 0;
605
606 $sql = "UPDATE cron_job SET ".
607 " job_status = ".$ilDB->quote(0, "integer").
608 " , job_status_user_id = ".$ilDB->quote($user_id, "integer").
609 " , job_status_type = ".$ilDB->quote($a_manual, "integer").
610 " , job_status_ts = ".$ilDB->quote(time(), "integer").
611 " WHERE job_id = ".$ilDB->quote($a_job->getId(), "text");
612 $ilDB->manipulate($sql);
613
614 $a_job->activationWasToggled(false);
615 }
616
623 public static function isJobActive($a_job_id)
624 {
625 $job = self::getCronJobData($a_job_id);
626 if((bool)$job[0]["job_status"])
627 {
628 return true;
629 }
630 return false;
631 }
632
639 public static function isJobInactive($a_job_id)
640 {
641 $job = self::getCronJobData($a_job_id);
642 if(!(bool)$job[0]["job_status"])
643 {
644 return true;
645 }
646 return false;
647 }
648
656 protected static function updateJobResult(ilCronJob $a_job, ilCronJobResult $a_result, $a_manual = false)
657 {
658 global $ilDB, $ilUser;
659
660 $user_id = $a_manual ? $ilUser->getId() : 0;
661
662 $sql = "UPDATE cron_job SET ".
663 " job_result_status = ".$ilDB->quote($a_result->getStatus(), "integer").
664 " , job_result_user_id = ".$ilDB->quote($user_id, "integer").
665 " , job_result_code = ".$ilDB->quote($a_result->getCode(), "text").
666 " , job_result_message = ".$ilDB->quote($a_result->getMessage(), "text").
667 " , job_result_type = ".$ilDB->quote($a_manual, "integer").
668 " , job_result_ts = ".$ilDB->quote(time(), "integer").
669 " , job_result_dur = ".$ilDB->quote($a_result->getDuration()*1000, "integer").
670 " WHERE job_id = ".$ilDB->quote($a_job->getId(), "text");
671 $ilDB->manipulate($sql);
672 }
673
681 public static function updateJobSchedule(ilCronJob $a_job, $a_schedule_type, $a_schedule_value)
682 {
683 global $ilDB;
684
685 if($a_schedule_type === null ||
686 ($a_job->hasFlexibleSchedule() &&
687 in_array($a_schedule_type, $a_job->getValidScheduleTypes())))
688 {
689 $sql = "UPDATE cron_job SET ".
690 " schedule_type = ".$ilDB->quote($a_schedule_type, "integer").
691 " , schedule_value = ".$ilDB->quote($a_schedule_value, "integer").
692 " WHERE job_id = ".$ilDB->quote($a_job->getId(), "text");
693 $ilDB->manipulate($sql);
694 }
695 }
696
702 protected static function getMicrotime()
703 {
704 list($usec, $sec) = explode(" ", microtime());
705 return ((float)$usec + (float)$sec);
706 }
707
713 public static function ping($a_job_id)
714 {
715 global $ilDB;
716
717 $ilDB->manipulate("UPDATE cron_job SET ".
718 " alive_ts = ".$ilDB->quote(time(), "integer").
719 " WHERE job_id = ".$ilDB->quote($a_job_id, "text"));
720 }
721}
722
723?>
$result
An exception for terminatinating execution or to throw for unit testing.
const IL_COMP_SERVICE
const IL_COMP_PLUGIN
Cron job result data container.
Cron job application base class.
getDefaultScheduleType()
Get schedule type.
activationWasToggled($a_currently_active)
Cron job status was changed.
run()
Run job.
getDefaultScheduleValue()
Get schedule value.
getId()
Get id.
isActive($a_ts_last_run, $a_schedule_type, $a_schedule_value, $a_manual=false)
Is job currently active?
hasAutoActivation()
Is to be activated on "installation".
hasFlexibleSchedule()
Can the schedule be configured?
getValidScheduleTypes()
Get all available schedule types.
Cron management.
static getCronJobData($a_id=null, $a_include_inactive=true)
Get cron job configuration/execution data.
static sendNotification(ilCronJob $a_job, $a_message)
Send notification to admin about job event(s)
static updateFromXML($a_component, $a_id, $a_class, $a_path=null)
Process data from module.xml/service.xml.
static createDefaultEntry(ilCronJob $a_job, $a_component, $a_class, $a_path)
static isJobInactive($a_job_id)
Check if given job is currently inactive.
static getJobInstanceById($a_job_id)
Get job instance (by job id)
static runJobManual($a_job_id)
Run single job manually.
static activateJob(ilCronJob $a_job, $a_manual=false)
Activate cron job.
static getJobInstance($a_id, $a_component, $a_class, $a_path=null)
Get job instance (by job data)
static isJobActive($a_job_id)
Check if given job is currently active.
static deactivateJob(ilCronJob $a_job, $a_manual=false)
Deactivate cron job.
static updateJobResult(ilCronJob $a_job, ilCronJobResult $a_result, $a_manual=false)
Save job result.
static clearFromXML($a_component, array $a_xml_job_ids)
Clear job data.
static resetJob(ilCronJob $a_job)
Reset job.
static ping($a_job_id)
Keep cron job alive.
static updateJobSchedule(ilCronJob $a_job, $a_schedule_type, $a_schedule_value)
Update job schedule.
static runJob(ilCronJob $a_job, array $a_job_data=null, $a_manual=false)
Run single cron job (internal)
static runActiveJobs()
Run all active jobs.
static getMicrotime()
Get current microtime.
static getPluginJobs($a_only_active=false)
ILIAS Setting Class.
static _getHttpPath()
defined( 'APPLICATION_ENV')||define( 'APPLICATION_ENV'
Definition: bootstrap.php:27
global $ilSetting
Definition: privfeed.php:17
global $ilDB
$ilUser
Definition: imgupload.php:18