]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - modules/Schedulers/SchedulerDaemon.php
Release 6.1.4
[Github/sugarcrm.git] / modules / Schedulers / SchedulerDaemon.php
1 <?php
2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4  * SugarCRM is a customer relationship management program developed by
5  * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc.
6  * 
7  * This program is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU Affero General Public License version 3 as published by the
9  * Free Software Foundation with the addition of the following permission added
10  * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11  * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12  * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
13  * 
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
17  * details.
18  * 
19  * You should have received a copy of the GNU Affero General Public License along with
20  * this program; if not, see http://www.gnu.org/licenses or write to the Free
21  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22  * 02110-1301 USA.
23  * 
24  * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25  * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
26  * 
27  * The interactive user interfaces in modified source and object code versions
28  * of this program must display Appropriate Legal Notices, as required under
29  * Section 5 of the GNU Affero General Public License version 3.
30  * 
31  * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32  * these Appropriate Legal Notices must retain the display of the "Powered by
33  * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34  * technical reasons, the Appropriate Legal Notices must display the words
35  * "Powered by SugarCRM".
36  ********************************************************************************/
37
38
39
40
41 class SchedulerDaemon extends Scheduler {
42         // schema columns
43         var $id;
44         var $deleted;
45         var $date_entered;
46         var $date_modified;
47         var $job_id;
48         var $execute_time;
49         // replicated SugarBean attributes
50         var $db;
51         // object attributes
52         var $object_name = 'SchedulerDaemon';
53         var $table_name = 'schedulers_times';
54         var $job_array;
55         var $watch_name; // this object's watch name
56         var $sleepInterval = 5; // how long to sleep before checking on jobs
57         var $lifespan = 45; // 2 mins to kill off this object
58         var $sessId; // admin PHPSESSID
59         var $runAsUserName; // admin user
60         var $runAsUserPassword; // admin pword
61         var $stop = false;
62         var $uptimeMonitor;
63         var $shutdown = false;
64
65         
66         /**
67          * Sole constructor.
68          */
69         function SchedulerDaemon () {
70                 if(empty($this->db)) {
71                         
72                         $this->db = DBManagerFactory::getInstance();
73                 }
74                         
75                 $GLOBALS['log']->debug('New Scheduler Instantiated.....................................');
76         }
77         
78
79
80
81
82
83         
84         /** 
85          * This function takes a look at the schedulers_times table and pulls the
86          * jobs to be run at this moment in time (anything not run and with a run
87          * time or earlier than right now)
88          * @return      $successful     Boolean flag whether a job(s) is found
89          */
90         function checkPendingJobs() {
91                 global $sugar_config;
92                 global $current_user;
93                 
94                 $GLOBALS['log']->debug('');
95                 $GLOBALS['log']->debug('----->Scheduler checking for qualified jobs to run.');
96                 if(empty($this->db)) {
97                         $this->db = DBManagerFactory::getInstance();
98                 }
99                 $fireTimeMinus = gmdate($GLOBALS['timedate']->get_db_date_time_format(), strtotime('now -1 min'));
100                 $fireTimePlus = gmdate($GLOBALS['timedate']->get_db_date_time_format(), strtotime('now +1 min'));
101                 
102                 // collapse list of schedulers where "catch_up" is 0 and status is "ready" (not "in progress, completed, etc.");
103                 if($sugar_config['dbconfig']['db_type'] == 'oci8') {
104                 } else  {
105                         $q = 'UPDATE schedulers_times st LEFT JOIN schedulers s ON st.scheduler_id = s.id SET st.status = \'not run\' WHERE st.execute_time < '.db_convert('\''.$fireTimeMinus.'\'', 'datetime').' AND st.status = \'ready\' AND s.catch_up = 0';
106                 }
107                 $this->db->query($q); 
108                 
109                 $q = 'SELECT DISTINCT st.id, st.scheduler_id, st.status, s.name, s.job FROM schedulers_times st LEFT JOIN schedulers s ON st.scheduler_id = s.id WHERE st.execute_time < '.db_convert('\''.$fireTimePlus.'\'', 'datetime').' AND st.deleted=0 AND s.deleted=0 AND st.status=\'ready\' AND s.status=\'Active\' ORDER BY s.name';
110                 $r = $this->db->query($q);
111                 $count = 0;
112                 
113                 if($sugar_config['dbconfig']['db_type'] == 'mysql') {
114                         $loopCount = $this->db->getRowCount($r);
115                         $GLOBALS['log']->debug('----->Scheduler has '.$loopCount.' jobs to fire.');
116                 }
117                 
118                 while($a = $this->db->fetchByAssoc($r)) {
119                         
120                         $job = new SchedulersJob();
121                         
122                         $paramJob = $a['scheduler_id'];
123                         $job->fire($sugar_config['site_url'].'/index.php?entryPoint=schedulers&type=job&job_id='.$paramJob.'&record='.$a['id']);
124                         $count++;
125                 }
126
127
128                 if($count < 1) {
129                         $GLOBALS['log']->debug('----->Scheduler has found 0 Jobs to fire');
130                 }
131         }
132         
133         /**
134          * This function takes a Scheduler object and uses its job_interval
135          * attribute to derive DB-standard datetime strings, as many as are
136          * qualified by its ranges.  The times are from the time of calling the
137          * script.
138          * 
139          * @param       $focus          Scheduler object
140          * @return      $dateTimes      array loaded with DB datetime strings derived from
141          *                                              the      job_interval attribute
142          * @return      false           If we the Scheduler is not in scope, return false.
143          */
144         function deriveDBDateTimes($focus) {
145                 $GLOBALS['log']->debug('deriveDBDateTimes got an object of type: '.$focus->object_name);
146                 /* [min][hr][dates][mon][days] */
147                 $dateTimes = array();
148                 $ints   = explode('::', str_replace(' ','',$focus->job_interval));
149                 $days   = $ints[4];
150                 $mons   = $ints[3];
151                 $dates  = $ints[2];
152                 $hrs    = $ints[1];
153                 $mins   = $ints[0];
154                 $today  = getdate(gmmktime());
155                 
156                 // derive day part
157                 if($days == '*') {
158                         $GLOBALS['log']->debug('got * day');
159
160                 } elseif(strstr($days, '*/')) {
161                         // the "*/x" format is nonsensical for this field
162                         // do basically nothing.
163                         $theDay = str_replace('*/','',$days);
164                         $dayName[] = str_replace($focus->dayInt, $focus->dayLabel, $theDay);
165                 } elseif($days != '*') { // got particular day(s)
166                         if(strstr($days, ',')) {
167                                 $exDays = explode(',',$days);
168                                 foreach($exDays as $k1 => $dayGroup) {
169                                         if(strstr($dayGroup,'-')) {
170                                                 $exDayGroup = explode('-', $dayGroup); // build up range and iterate through
171                                                 for($i=$exDayGroup[0];$i<=$exDayGroup[1];$i++) {
172                                                         $dayName[] = str_replace($focus->dayInt, $focus->dayLabel, $i);
173                                                 }
174                                         } else { // individuals
175                                                 $dayName[] = str_replace($focus->dayInt, $focus->dayLabel, $dayGroup);
176                                         }
177                                 }
178                         } elseif(strstr($days, '-')) {
179                                 $exDayGroup = explode('-', $days); // build up range and iterate through
180                                 for($i=$exDayGroup[0];$i<=$exDayGroup[1];$i++) {
181                                         $dayName[] = str_replace($focus->dayInt, $focus->dayLabel, $i);
182                                 }
183                         } else {
184                                 $dayName[] = str_replace($focus->dayInt, $focus->dayLabel, $days);
185                         }
186                         
187                         // check the day to be in scope:
188                         if(!in_array($today['weekday'], $dayName)) {
189                                 return false;
190                         }
191                 } else {
192                         return false;
193                 }
194                 
195                 
196                 // derive months part
197                 if($mons == '*') {
198                         $GLOBALS['log']->debug('got * months');
199                 } elseif(strstr($mons, '*/')) {
200                         $mult = str_replace('*/','',$mons);
201                         $startMon = date(strtotime('m',$focus->date_time_start));
202                         $startFrom = ($startMon % $mult);
203
204                         for($i=$startFrom;$i<=12;$i+$mult) {
205                                 $compMons[] = $i+$mult;
206                                 $i += $mult;
207                         }
208                         // this month is not in one of the multiplier months
209                         if(!in_array($today['mon'],$compMons)) {
210                                 return false;   
211                         }
212                 } elseif($mons != '*') {
213                         if(strstr($mons,',')) { // we have particular (groups) of months
214                                 $exMons = explode(',',$mons);
215                                 foreach($exMons as $k1 => $monGroup) {
216                                         if(strstr($monGroup, '-')) { // we have a range of months
217                                                 $exMonGroup = explode('-',$monGroup);
218                                                 for($i=$exMonGroup[0];$i<=$exMonGroup[1];$i++) {
219                                                         $monName[] = $i;
220                                                 }
221                                         } else {
222                                                 $monName[] = $monGroup;
223                                         }
224                                 }
225                         } elseif(strstr($mons, '-')) {
226                                 $exMonGroup = explode('-', $mons);
227                                 for($i=$exMonGroup[0];$i<=$exMonGroup[1];$i++) {
228                                         $monName[] = $i;
229                                 }
230                         } else { // one particular month
231                                 $monName[] = $mons;
232                         }
233                         
234                         // check that particular months are in scope
235                         if(!in_array($today['mon'], $monName)) {
236                                 return false;
237                         }
238                 }
239
240                 // derive dates part
241                 if($dates == '*') {
242                         $GLOBALS['log']->debug('got * dates');
243                 } elseif(strstr($dates, '*/')) {
244                         $mult = str_replace('*/','',$dates);
245                         $startDate = date('d', strtotime($focus->date_time_start));
246                         $startFrom = ($startDate % $mult);
247
248                         for($i=$startFrom; $i<=31; $i+$mult) {
249                                 $dateName[] = str_pad(($i+$mult),2,'0',STR_PAD_LEFT);
250                                 $i += $mult;
251                         }
252                         
253                         if(!in_array($today['mday'], $dateName)) {
254                                 return false;   
255                         }
256                 } elseif($dates != '*') {
257                         if(strstr($dates, ',')) {
258                                 $exDates = explode(',', $dates);
259                                 foreach($exDates as $k1 => $dateGroup) {
260                                         if(strstr($dateGroup, '-')) {
261                                                 $exDateGroup = explode('-', $dateGroup);
262                                                 for($i=$exDateGroup[0];$i<=$exDateGroup[1];$i++) {
263                                                         $dateName[] = $i; 
264                                                 }
265                                         } else {
266                                                 $dateName[] = $dateGroup;
267                                         }
268                                 }
269                         } elseif(strstr($dates, '-')) {
270                                 $exDateGroup = explode('-', $dates);
271                                 for($i=$exDateGroup[0];$i<=$exDateGroup[1];$i++) {
272                                         $dateName[] = $i; 
273                                 }
274                         } else {
275                                 $dateName[] = $dates;
276                         }
277                         
278                         // check that dates are in scope
279                         if(!in_array($today['mday'], $dateName)) {
280                                 return false;
281                         }
282                 }
283                 
284                 // derive hours part
285                 //$startHour = date('G', strtotime($focus->date_time_start));
286                 //$currentHour = ($startHour < 1) ? 23 : date('G', strtotime($focus->date_time_start));
287                 $currentHour = date('G');
288                 if($hrs == '*') {
289                         $GLOBALS['log']->debug('got * hours');
290                         for($i=0;$i<=24; $i++) {
291                                 if($currentHour + $i > 23) {
292                                         $hrName[] = $currentHour + $i - 24;
293                                 } else {
294                                         $hrName[] = $currentHour + $i;
295                                 }
296                         }
297                 } elseif(strstr($hrs, '*/')) {
298                         $mult = str_replace('*/','',$hrs);
299                         for($i=0; $i<24; $i) { // weird, i know
300                                 if($currentHour + $i > 23) {
301                                         $hrName[] = $currentHour + $i - 24;
302                                 } else {
303                                         $hrName[] = $currentHour + $i;
304                                 }
305                                 $i += $mult;
306                         }
307                 } elseif($hrs != '*') {
308                         if(strstr($hrs, ',')) {
309                                 $exHrs = explode(',',$hrs);
310                                 foreach($exHrs as $k1 => $hrGroup) {
311                                         if(strstr($hrGroup, '-')) {
312                                                 $exHrGroup = explode('-', $hrGroup);
313                                                 for($i=$exHrGroup[0];$i<=$exHrGroup[1];$i++) {
314                                                         $hrName[] = $i;
315                                                 }
316                                         } else {
317                                                 $hrName[] = $hrGroup;
318                                         }
319                                 }
320                         } elseif(strstr($hrs, '-')) {
321                                 $exHrs = explode('-', $hrs);
322                                 for($i=$exHrs[0];$i<=$exHrs[1];$i++) {
323                                         $hrName[] = $i;
324                                 }
325                         } else {
326                                 $hrName[] = $hrs;
327                         }
328                 }
329                 // derive minutes
330                 $currentMin = date('i');
331                 if(substr($currentMin, 0, 1) == '0') {
332                         $currentMin = substr($currentMin, 1, 1);
333                 }
334                 if($mins == '*') {
335                         $GLOBALS['log']->debug('got * mins');
336                         for($i=0; $i<60; $i++) {
337                                 if(($currentMin + $i) > 59) {
338                                         $minName[] = ($i + $currentMin - 60);
339                                 } else {
340                                         $minName[] = ($i+$currentMin);
341                                 }
342                         }
343                 } elseif(strstr($mins,'*/')) {
344                         $mult = str_replace('*/','',$mins);
345                         $startMin = date('i',strtotime($focus->date_time_start));
346                         $startFrom = ($startMin % $mult);
347                         
348                         for($i=$startFrom; $i<=59; $i+$mult) {
349                                 if(($currentMin + $i) > 59) {
350                                         $minName[] = ($i + $currentMin - 60);
351                                 } else {
352                                         $minName[] = ($i+$currentMin);
353                                 }
354                                 $i += $mult;
355                         }
356                 } elseif($mins != '*') {
357                         if(strstr($mins, ',')) {
358                                 $exMins = explode(',',$mins);
359                                 foreach($exMins as $k1 => $minGroup) {
360                                         if(strstr($minGroup, '-')) {
361                                                 $exMinGroup = explode('-', $minGroup);
362                                                 for($i=$exMinGroup[0]; $i<=$exMinGroup[1]; $i++) {
363                                                         $minName[] = $i;
364                                                 }
365                                         } else {
366                                                 $minName[] = $minGroup;
367                                         }
368                                 }
369                         } elseif(strstr($mins, '-')) {
370                                 $exMinGroup = explode('-', $mins);
371                                 for($i=$exMinGroup[0]; $i<=$exMinGroup[1]; $i++) {
372                                         $minName[] = $i;
373                                 }
374                         } else {
375                                 $minName[] = $mins;
376                         }
377                 } 
378                 
379                 // prep some boundaries - these are not in GMT b/c gmt is a 24hour period, possibly bridging 2 local days
380                 if(empty($focus->time_from)  && empty($focus->time_to) ) {
381                         $timeFromTs = 0;
382                         $timeToTs = strtotime('+1 day');
383                 } else {
384                         $timeFromTs = strtotime($focus->time_from);     // these are now GMT (timestamps are all GMT)
385                         $timeToTs       = strtotime($focus->time_to);   // see above
386                         if($timeFromTs > $timeToTs) { // we've crossed into the next day 
387                                 $timeToTs = strtotime('+1 day '. $focus->time_to);      // also in GMT
388                         }
389                 }
390                 $timeToTs++;
391                 
392                 if(empty($focus->last_run)) {
393                         $lastRunTs = 0;
394                 } else {
395                         $lastRunTs = strtotime($focus->last_run);
396                 }
397
398                 
399                 // now smush the arrays together =)
400                 $validJobTime = array();
401                 global $timedate;
402                 $dts = explode(' ',$focus->date_time_start); // split up datetime field into date & time
403                 
404                 $dts2 = $timedate->to_db_date_time($dts[0],$dts[1]); // get date/time into DB times (GMT)
405                 $dateTimeStart = $dts2[0]." ".$dts2[1];
406                 $timeStartTs = strtotime($dateTimeStart);
407                 if(!empty($focus->date_time_end) && !$focus->date_time_end == '2021-01-01 07:59:00') { // do the same for date_time_end if not empty
408                         $dte = explode(' ', $focus->date_time_end);
409                         $dte2 = $timedate->to_db_date_time($dte[0],$dte[1]);
410                         $dateTimeEnd = $dte2[0]." ".$dte2[1];
411                 } else {
412                         $dateTimeEnd = date('Y-m-d H:i:s', strtotime('+1 day'));
413 //                      $dateTimeEnd = '2020-12-31 23:59:59'; // if empty, set it to something ridiculous
414                 }
415                 $timeEndTs = strtotime($dateTimeEnd); // GMT end timestamp if necessary
416                 $timeEndTs++;
417                 /*_pp('hours:'); _pp($hrName);_pp('mins:'); _pp($minName);*/
418                 $nowTs = mktime();
419
420 //              _pp('currentHour: '. $currentHour);
421 //              _pp('timeStartTs: '.date('r',$timeStartTs));
422 //              _pp('timeFromTs: '.date('r',$timeFromTs));
423 //              _pp('timeEndTs: '.date('r',$timeEndTs));
424 //              _pp('timeToTs: '.date('r',$timeToTs));
425 //              _pp('mktime: '.date('r',mktime()));
426 //              _pp('timeLastRun: '.date('r',$lastRunTs));
427 //              
428 //              _pp('hours: ');
429 //              _pp($hrName);
430 //              _pp('mins: ');
431 //              _ppd($minName);
432                 $hourSeen = 0;
433                 foreach($hrName as $kHr=>$hr) {
434                         $hourSeen++;
435                         foreach($minName as $kMin=>$min) {
436                                 if($hr < $currentHour || $hourSeen == 25) {
437                                         $theDate = date('Y-m-d', strtotime('+1 day'));
438                                 } else {
439                                         $theDate = date('Y-m-d');
440                                 }
441
442                                 $tsGmt = strtotime($theDate.' '.str_pad($hr,2,'0',STR_PAD_LEFT).":".str_pad($min,2,'0',STR_PAD_LEFT).":00"); // this is LOCAL
443 //                              _pp(date('Y-m-d H:i:s',$tsGmt));
444                                 
445                                 if( $tsGmt >= $timeStartTs ) { // start is greater than the date specified by admin
446                                         if( $tsGmt >= $timeFromTs ) { // start is greater than the time_to spec'd by admin
447                                                 if( $tsGmt <= $timeEndTs ) { // this is taken care of by the initial query - start is less than the date spec'd by admin
448                                                         if( $tsGmt <= $timeToTs ) { // start is less than the time_to
449                                                                 if( $tsGmt >= $nowTs ) { // we only want to add jobs that are in the future
450                                                                         if( $tsGmt > $lastRunTs ) { //TODO figure if this is better than the above check
451                                                                                 $validJobTime[] = gmdate('Y-m-d H:i:s', $tsGmt);
452                                                                                 //_pp("Job Qualified for: ".date('Y-m-d H:i:s', $tsGmt));
453                                                                         } else {
454                                                                                 //_pp('Job Time is NOT greater than Last Run');
455                                                                         }
456                                                                 } else {
457                                                                         //_pp('Job Time is NOT larger than NOW'); _pp(date('Y-m-d H:i:s', $nowTs));
458                                                                 }
459                                                         } else {
460                                                                 //_pp('Job Time is NOT smaller that TimeTO: '.$tsGmt .'<='. $timeToTs); 
461                                                         }
462                                                 } else {
463                                                         //_pp('Job Time is NOT smaller that DateTimeEnd: '.date('Y-m-d H:i:s',$tsGmt) .'<='. $dateTimeEnd); _pp( $tsGmt .'<='. $timeEndTs );
464                                                 }
465                                         } else {
466                                                 //_pp('Job Time is NOT bigger that TimeFrom: '.$tsGmt .'>='. $timeFromTs);
467                                         }
468                                 } else {
469                                         //_pp('Job Time is NOT Bigger than DateTimeStart: '.date('Y-m-d H:i',$tsGmt) .'>='. $dateTimeStart);
470                                 }
471                         }
472                 }
473 //              _ppd();
474 //              _ppd($validJobTime);
475                 return $validJobTime;
476                 
477         }
478
479         /**
480          * This function takes an array of jobs build up by retrieveSchedulers and
481          * puts them into the schedulers_times table
482          */
483         function insertSchedules() {
484                 $GLOBALS['log']->info('----->Scheduler retrieving scheduled items and adding them to Job queue.');
485                 $jobsArr = $this->retrieveSchedulers();
486                 if(is_array($jobsArr['ids']) && !empty($jobsArr['ids']) && is_array($jobsArr['times']) && !empty($jobsArr['times'])) {
487                         foreach($jobsArr['ids'] as $k => $ids) {
488                                 foreach($jobsArr['times'][$k] as $j => $time) {
489                                         $guid = create_guid();
490                                         $q = "INSERT INTO schedulers_times
491                                                 (id, deleted, date_entered, date_modified, scheduler_id, execute_time, status)
492                                                 VALUES (
493                                                 '".$guid."',
494                                                 0, 
495                                                 ".db_convert("'".gmdate($GLOBALS['timedate']->get_db_date_time_format())."'", 'datetime').",
496                                                 ".db_convert("'".gmdate($GLOBALS['timedate']->get_db_date_time_format())."'", 'datetime').",
497                                                 '".$jobsArr['ids'][$k]."',
498                                                 ".db_convert("'".$time."'", 'datetime').",
499                                                 'ready'
500                                                 )";
501                                                 $this->db->query($q);
502                                         $GLOBALS['log']->info('Query: '.$q);
503                                 }
504                         }
505                 }
506         }
507
508         /**
509          * This function drops all rows in the schedulers_times table.
510          */
511         function dropSchedules($truncate=false) {
512                 global $sugar_config;
513                 
514                 if(empty($this->db)) {
515                         $this->db = DBManagerFactory::getInstance();    
516                 }
517                 
518                 if($truncate) {
519                         if($sugar_config['dbconfig']['db_type'] == 'oci8') {
520                         } else {
521                                 $query = 'TRUNCATE schedulers_times';
522                         }
523                         $this->db->query($query);
524                         $GLOBALS['log']->debug('----->Scheduler TRUNCATED ALL Jobs: '.$query);
525                 } else {
526                         $query = 'UPDATE schedulers_times SET deleted = 1';
527                         $this->db->query($query);
528                         $GLOBALS['log']->debug('----->Scheduler soft deleting all Jobs: '.$query);
529                 }
530                 //TODO make sure this will fail gracefully
531         }
532         
533         /**
534          * This function retrieves valid jobs, parses the cron format, then returns
535          * an array of [JOB_ID][EXEC_TIME][JOB]
536          * 
537          * @return      $executeJobs    multi-dimensional array 
538          *                                                      [job_id][execute_time]
539          */
540         function retrieveSchedulers() {
541                 $GLOBALS['log']->info('Gathering Schedulers');
542                 $executeJobs = array();
543                 $query  = "SELECT id " .
544                                 "FROM schedulers " .
545                                 "WHERE deleted=0 " .
546                                 "AND status = 'Active' " .
547                                 "AND date_time_start < ".db_convert("'".gmdate($GLOBALS['timedate']->get_db_date_time_format())."'",'datetime')." " .
548                                 "AND (date_time_end > ".db_convert("'".gmdate($GLOBALS['timedate']->get_db_date_time_format())."'",'datetime')." OR date_time_end IS NULL)";
549                                 
550                 $result = $this->db->query($query);
551                 $rows=0;
552                 $executeTimes = array();
553                 $executeIds = array();
554                 $executeJobTimes = array();
555                 while(($arr = $this->db->fetchByAssoc($result)) != null) {
556                         $focus = new Scheduler();
557                         $focus->retrieve($arr['id']);
558                         $executeTimes[$rows] = $this->deriveDBDateTimes($focus);
559                         if(count($executeTimes) > 0) {
560                                 foreach($executeTimes as $k => $time) {
561                                 $executeIds[$rows] = $focus->id;
562                                         $executeJobTimes[$rows] = $time;
563                                 }
564                         }
565                         $rows++;
566                 }
567                 $executeJobs['ids'] = $executeIds;
568                 $executeJobs['times'] = $executeJobTimes;
569                 return $executeJobs;
570         }
571
572 } // end SchedulerDaemon class desc.
573
574 ?>