ILIAS  release_5-1 Revision 5.0.0-5477-g43f3e3fab5f
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 if($a_job_data === null)
104 {
105 // aquire "fresh" job (status) data
106 $a_job_data = array_pop(self::getCronJobData($a_job->getId()));
107 }
108
109 if($a_job)
110 {
111 include_once "Services/Cron/classes/class.ilCronJobResult.php";
112
113 // already running?
114 if($a_job_data["alive_ts"])
115 {
116 $ilLog->write("CRON - job ".$a_job_data["job_id"]." still running");
117
118 $cut = 60*60*3; // 3h
119
120 // is running (and has not pinged) for 3 hours straight, we assume it crashed
121 if(time()-$a_job_data["alive_ts"] > $cut)
122 {
123 $ilDB->manipulate("UPDATE cron_job SET".
124 " running_ts = ".$ilDB->quote(0, "integer").
125 " , alive_ts = ".$ilDB->quote(0, "integer").
126 " WHERE job_id = ".$ilDB->quote($a_job_data["job_id"], "text"));
127
128 self::deactivateJob($a_job); // #13082
129
130 $result = new ilCronJobResult();
132 $result->setCode("job_auto_deactivation_time_limit");
133 $result->setMessage("Cron job deactivated because it has been inactive for 3 hours");
134
135 if(!$a_manual)
136 {
138 }
139
140 self::updateJobResult($a_job, $result, $a_manual);
141
142 $ilLog->write("CRON - job ".$a_job_data["job_id"]." deactivated (assumed crash)");
143 }
144 }
145 // initiate run?
146 else if($a_job->isActive($a_job_data["job_result_ts"],
147 $a_job_data["schedule_type"], $a_job_data["schedule_value"], $a_manual))
148 {
149 $ilLog->write("CRON - job ".$a_job_data["job_id"]." started");
150
151 $ilDB->manipulate("UPDATE cron_job SET".
152 " running_ts = ".$ilDB->quote(time(), "integer").
153 " , alive_ts = ".$ilDB->quote(time(), "integer").
154 " WHERE job_id = ".$ilDB->quote($a_job_data["job_id"], "text"));
155
156 $ts_in = self::getMicrotime();
157 $result = $a_job->run();
158 $ts_dur = self::getMicrotime()-$ts_in;
159
160 // no proper result
161 if(!$result instanceof ilCronJobResult)
162 {
163 $result = new ilCronJobResult();
165 $result->setCode("job_no_result");
166 $result->setMessage("Cron job did not return a proper result");
167
168 if(!$a_manual)
169 {
171 }
172
173 $ilLog->write("CRON - job ".$a_job_data["job_id"]." no result");
174 }
175 // no valid configuration, job won't work
177 {
178 self::deactivateJob($a_job);
179
180 if(!$a_manual)
181 {
183 }
184
185 $ilLog->write("CRON - job ".$a_job_data["job_id"]." invalid configuration");
186 }
187 // success!
188 else
189 {
190 $did_run = true;
191 }
192
193 $result->setDuration($ts_dur);
194
195 self::updateJobResult($a_job, $result, $a_manual);
196
197 $ilDB->manipulate("UPDATE cron_job SET".
198 " running_ts = ".$ilDB->quote(0, "integer").
199 " , alive_ts = ".$ilDB->quote(0, "integer").
200 " WHERE job_id = ".$ilDB->quote($a_job_data["job_id"], "text"));
201
202 $ilLog->write("CRON - job ".$a_job_data["job_id"]." finished");
203 }
204 else
205 {
206 $ilLog->write("CRON - job ".$a_job_data["job_id"]." returned status inactive");
207 }
208 }
209
210 return $did_run;
211 }
212
219 public static function getJobInstanceById($a_job_id)
220 {
221 global $ilLog, $ilPluginAdmin;
222
223 // plugin
224 if(substr($a_job_id, 0, 4) == "pl__")
225 {
226 $parts = explode("__", $a_job_id);
227 $pl_name = $parts[1];
228 $job_id = $parts[2];
229 if($ilPluginAdmin->isActive(IL_COMP_SERVICE, "Cron", "crnhk", $pl_name))
230 {
231 $plugin_obj = $ilPluginAdmin->getPluginObject(IL_COMP_SERVICE,
232 "Cron", "crnhk", $pl_name);
233 $job = $plugin_obj->getCronJobInstance($job_id);
234 if($job instanceof ilCronJob)
235 {
236 // should never happen but who knows...
237 if(!sizeof(ilCronManager::getCronJobData($job_id)))
238 {
239 // as job is not "imported" from xml
241 }
242 return $job;
243 }
244 }
245
246 return null;
247 }
248 // system
249 else
250 {
251 $job_data = array_pop(self::getCronJobData($a_job_id));
252 if($job_data["job_id"] == $a_job_id)
253 {
254 return self::getJobInstance($job_data["job_id"], $job_data["component"],
255 $job_data["class"], $job_data["path"]);
256 }
257 }
258
259 $ilLog->write("CRON - job ".$a_job_id." seems invalid or is inactive");
260 }
261
270 public static function getJobInstance($a_id, $a_component, $a_class, $a_path = null)
271 {
272 global $ilLog;
273
274 if(!$a_path)
275 {
276 $a_path = $a_component."/classes/";
277 }
278 $class_file = $a_path."class.".$a_class.".php";
279 if(file_exists($class_file))
280 {
281 include_once $class_file;
282 if(class_exists($a_class))
283 {
284 $job = new $a_class();
285 if($job instanceof ilCronJob)
286 {
287 if($job->getId() == $a_id)
288 {
289 return $job;
290 }
291 else
292 {
293 $mess .= " - job id mismatch";
294 }
295 }
296 else
297 {
298 $mess .= " - does not extend ilCronJob";
299 }
300 }
301 else
302 {
303 $mess = "- class not found in file";
304 }
305 }
306 else
307 {
308 $mess = " - class file not found";
309 }
310
311 $ilLog->write("Cron XML - Job ".$a_id." in class ".$a_class." (".
312 $class_file.") is invalid.".$mess);
313 }
314
321 protected static function sendNotification(ilCronJob $a_job, $a_message)
322 {
323 // :TODO:
324 }
325
326 public static function createDefaultEntry(ilCronJob $a_job, $a_component, $a_class, $a_path)
327 {
328 global $ilDB, $ilLog, $ilSetting;
329
330 // already exists?
331 $sql = "SELECT job_id, schedule_type FROM cron_job".
332 " WHERE component = ".$ilDB->quote($a_component, "text").
333 " AND job_id = ".$ilDB->quote($a_job->getId(), "text");
334 $set = $ilDB->query($sql);
335 $row = $ilDB->fetchAssoc($set);
336 $job_exists = ($row["job_id"] == $a_job->getId());
337 $schedule_type = $row["schedule_type"];
338
339 // new job
340 if(!$job_exists)
341 {
342 $sql = "INSERT INTO cron_job (job_id, component, class, path)".
343 " VALUES (".$ilDB->quote($a_job->getId(), "text").", ".
344 $ilDB->quote($a_component, "text").", ".
345 $ilDB->quote($a_class, "text").", ".
346 $ilDB->quote($a_path, "text").")";
347 $ilDB->manipulate($sql);
348
349 $ilLog->write("Cron XML - Job ".$a_job->getId()." in class ".$a_class.
350 " added.");
351
352 // only if flexible
354 $a_job->getDefaultScheduleType(),
355 $a_job->getDefaultScheduleValue());
356
357 // #12221
358 if(!is_object($ilSetting))
359 {
360 include_once "Services/Administration/classes/class.ilSetting.php";
361 $ilSetting = new ilSetting();
362 }
363
364 if($a_job->hasAutoActivation())
365 {
366 self::activateJob($a_job);
367 }
368 else
369 {
370 // to overwrite dependent settings
371 $a_job->activationWasToggled(false);
372 }
373 }
374 // existing job - but schedule is flexible now
375 else if($a_job->hasFlexibleSchedule() && !$schedule_type)
376 {
378 $a_job->getDefaultScheduleType(),
379 $a_job->getDefaultScheduleValue());
380 }
381 // existing job - but schedule is static now
382 else if(!$a_job->hasFlexibleSchedule() && $schedule_type)
383 {
384 self::updateJobSchedule($a_job, null, null);
385 }
386 }
387
396 public static function updateFromXML($a_component, $a_id, $a_class, $a_path = null)
397 {
398 global $ilDB;
399
400 if(!$ilDB->tableExists("cron_job"))
401 {
402 return;
403 }
404
405 // only if job seems valid
406 $job = self::getJobInstance($a_id, $a_component, $a_class, $a_path);
407 if($job)
408 {
409 self::createDefaultEntry($job, $a_component, $a_class, $a_path);
410 }
411 }
412
419 public static function clearFromXML($a_component, array $a_xml_job_ids)
420 {
421 global $ilDB, $ilLog;
422
423 if(!$ilDB->tableExists("cron_job"))
424 {
425 return;
426 }
427
428 // gather existing jobs
429 $all_jobs = array();
430 $sql = "SELECT job_id FROM cron_job".
431 " WHERE component = ".$ilDB->quote($a_component, "text");
432 $set = $ilDB->query($sql);
433 while($row = $ilDB->fetchAssoc($set))
434 {
435 $all_jobs[] = $row["job_id"];
436 }
437
438 if(sizeof($all_jobs))
439 {
440 if(sizeof($a_xml_job_ids))
441 {
442 // delete obsolete job data
443 foreach($all_jobs as $job_id)
444 {
445 if(!in_array($job_id, $a_xml_job_ids))
446 {
447 $ilDB->manipulate("DELETE FROM cron_job".
448 " WHERE component = ".$ilDB->quote($a_component, "text").
449 " AND job_id = ".$ilDB->quote($job_id, "text"));
450
451 $ilLog->write("Cron XML - Job ".$job_id." in class ".$a_component.
452 " deleted.");
453 }
454 }
455 }
456 else
457 {
458 $ilDB->manipulate("DELETE FROM cron_job".
459 " WHERE component = ".$ilDB->quote($a_component, "text"));
460
461 $ilLog->write("Cron XML - All jobs deleted for ".$a_component." as component is inactive.");
462 }
463 }
464 }
465
466 public static function getPluginJobs($a_only_active = false)
467 {
468 global $ilPluginAdmin;
469
470 $res = array();
471
472 foreach($ilPluginAdmin->getActivePluginsForSlot(IL_COMP_SERVICE, "Cron", "crnhk") as $pl_name)
473 {
474 $plugin_obj = $ilPluginAdmin->getPluginObject(IL_COMP_SERVICE, "Cron", "crnhk", $pl_name);
475
476 foreach((array)$plugin_obj->getCronJobInstances() as $job)
477 {
478 $item = array_pop(ilCronManager::getCronJobData($job->getId()));
479 if(!sizeof($item))
480 {
481 // as job is not "imported" from xml
483 }
484
485 $item = array_pop(ilCronManager::getCronJobData($job->getId()));
486
487 // #17941
488 if(!$a_only_active ||
489 $item["job_status"] == 1)
490 {
491 $res[$job->getId()] = array($job, $item);
492 }
493 }
494 }
495
496 return $res;
497 }
498
506 public static function getCronJobData($a_id = null, $a_include_inactive = true)
507 {
508 global $ilDB;
509
510 $res = array();
511
512 if($a_id && !is_array($a_id))
513 {
514 $a_id = array($a_id);
515 }
516
517 $sql = "SELECT * FROM cron_job";
518
519 $where = array();
520 if($a_id)
521 {
522 $where[] = $ilDB->in("job_id", $a_id, "", "text");
523 }
524 else
525 {
526 $where[] = "class <> ".$ilDB->quote(IL_COMP_PLUGIN, "text");
527 }
528 if(!$a_include_inactive)
529 {
530 $where[] = "job_status = ".$ilDB->quote(1, "integer");
531 }
532 if(sizeof($where))
533 {
534 $sql .= " WHERE ".implode(" AND ", $where);
535 }
536
537 // :TODO: discuss job execution order
538 $sql .= " ORDER BY job_id";
539
540 $set = $ilDB->query($sql);
541 while($row = $ilDB->fetchAssoc($set))
542 {
543 $res[] = $row;
544 }
545
546 return $res;
547 }
548
554 public static function resetJob(ilCronJob $a_job)
555 {
556 global $ilDB;
557
558 include_once "Services/Cron/classes/class.ilCronJobResult.php";
559 $result = new ilCronJobResult();
561 $result->setCode("job_manual_reset");
562 $result->setMessage("Cron job re-activated by admin");
563 self::updateJobResult($a_job, $result, true);
564
565 $ilDB->manipulate("UPDATE cron_job".
566 " SET running_ts = ".$ilDB->quote(0, "integer").
567 " , alive_ts = ".$ilDB->quote(0, "integer").
568 " , job_result_ts = ".$ilDB->quote(0, "integer").
569 " WHERE job_id = ".$ilDB->quote($a_job->getId(), "text"));
570
571 self::activateJob($a_job, true);
572 }
573
580 public static function activateJob(ilCronJob $a_job, $a_manual = false)
581 {
582 global $ilDB, $ilUser;
583
584 $user_id = $a_manual ? $ilUser->getId() : 0;
585
586 $sql = "UPDATE cron_job SET ".
587 " job_status = ".$ilDB->quote(1, "integer").
588 " , job_status_user_id = ".$ilDB->quote($user_id, "integer").
589 " , job_status_type = ".$ilDB->quote($a_manual, "integer").
590 " , job_status_ts = ".$ilDB->quote(time(), "integer").
591 " WHERE job_id = ".$ilDB->quote($a_job->getId(), "text");
592 $ilDB->manipulate($sql);
593
594 $a_job->activationWasToggled(true);
595 }
596
603 public static function deactivateJob(ilCronJob $a_job, $a_manual = false)
604 {
605 global $ilDB, $ilUser;
606
607 $user_id = $a_manual ? $ilUser->getId() : 0;
608
609 $sql = "UPDATE cron_job SET ".
610 " job_status = ".$ilDB->quote(0, "integer").
611 " , job_status_user_id = ".$ilDB->quote($user_id, "integer").
612 " , job_status_type = ".$ilDB->quote($a_manual, "integer").
613 " , job_status_ts = ".$ilDB->quote(time(), "integer").
614 " WHERE job_id = ".$ilDB->quote($a_job->getId(), "text");
615 $ilDB->manipulate($sql);
616
617 $a_job->activationWasToggled(false);
618 }
619
626 public static function isJobActive($a_job_id)
627 {
628 $job = self::getCronJobData($a_job_id);
629 if((bool)$job[0]["job_status"])
630 {
631 return true;
632 }
633 return false;
634 }
635
642 public static function isJobInactive($a_job_id)
643 {
644 $job = self::getCronJobData($a_job_id);
645 if(!(bool)$job[0]["job_status"])
646 {
647 return true;
648 }
649 return false;
650 }
651
659 protected static function updateJobResult(ilCronJob $a_job, ilCronJobResult $a_result, $a_manual = false)
660 {
661 global $ilDB, $ilUser;
662
663 $user_id = $a_manual ? $ilUser->getId() : 0;
664
665 $sql = "UPDATE cron_job SET ".
666 " job_result_status = ".$ilDB->quote($a_result->getStatus(), "integer").
667 " , job_result_user_id = ".$ilDB->quote($user_id, "integer").
668 " , job_result_code = ".$ilDB->quote($a_result->getCode(), "text").
669 " , job_result_message = ".$ilDB->quote($a_result->getMessage(), "text").
670 " , job_result_type = ".$ilDB->quote($a_manual, "integer").
671 " , job_result_ts = ".$ilDB->quote(time(), "integer").
672 " , job_result_dur = ".$ilDB->quote($a_result->getDuration()*1000, "integer").
673 " WHERE job_id = ".$ilDB->quote($a_job->getId(), "text");
674 $ilDB->manipulate($sql);
675 }
676
684 public static function updateJobSchedule(ilCronJob $a_job, $a_schedule_type, $a_schedule_value)
685 {
686 global $ilDB;
687
688 if($a_schedule_type === null ||
689 ($a_job->hasFlexibleSchedule() &&
690 in_array($a_schedule_type, $a_job->getValidScheduleTypes())))
691 {
692 $sql = "UPDATE cron_job SET ".
693 " schedule_type = ".$ilDB->quote($a_schedule_type, "integer").
694 " , schedule_value = ".$ilDB->quote($a_schedule_value, "integer").
695 " WHERE job_id = ".$ilDB->quote($a_job->getId(), "text");
696 $ilDB->manipulate($sql);
697 }
698 }
699
705 protected static function getMicrotime()
706 {
707 list($usec, $sec) = explode(" ", microtime());
708 return ((float)$usec + (float)$sec);
709 }
710
716 public static function ping($a_job_id)
717 {
718 global $ilDB;
719
720 $ilDB->manipulate("UPDATE cron_job SET ".
721 " alive_ts = ".$ilDB->quote(time(), "integer").
722 " WHERE job_id = ".$ilDB->quote($a_job_id, "text"));
723 }
724}
725
726?>
$result
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()
global $ilSetting
Definition: privfeed.php:40
global $ilDB
global $ilUser
Definition: imgupload.php:15