source: trunk/workflow/inc/class.JobScheduler.inc.php @ 795

Revision 795, 6.5 KB checked in by viani, 15 years ago (diff)

Ticket #488 - Inclusão do módulo workflow no ramo trunk do repositório Expresso.

Line 
1<?php
2/**************************************************************************\
3* eGroupWare                                                               *
4* http://www.egroupware.org                                                *
5* --------------------------------------------                             *
6*  This program is free software; you can redistribute it and/or modify it *
7*  under the terms of the GNU General Public License as published by the   *
8*  Free Software Foundation; either version 2 of the License, or (at your  *
9*  option) any later version.                                              *
10\**************************************************************************/
11
12require_once 'jobs/class.JobEnum.inc.php';
13require_once 'jobs/class.AbsoluteDate.inc.php';
14require_once 'jobs/class.WeekDate.inc.php';
15require_once 'jobs/class.RelativeDate.inc.php';
16
17/**
18 * Classe que verifica se um Job deve ser executado neste momento. E, em caso positivo, dispara sua execução
19 * @author Sidnei Augusto Drovetto Junior - drovetto@gmail.com
20 * @version 1.0
21 * @license http://www.gnu.org/copyleft/gpl.html GPL
22 * @package Workflow
23 * @subpackage Job
24 */
25class JobScheduler
26{
27        /**
28         * @var object $currentDate A data corrente (truncada nos minutos)
29         * @access private
30         */
31        private $currentDate;
32
33        /**
34         * @var object $db Objeto de conexão com o Banco de Dados
35         * @access private
36         */
37        private $db;
38
39        /**
40         * @var object $jobManager Objeto da classe JobManager
41         * @access private
42         */
43        private $jobManager;
44
45        /**
46         * Tempo máximo de execução de um Job (em microsegundos)
47         * @name MAXIMUM_EXECUTION_TIME
48         */
49        const MAXIMUM_EXECUTION_TIME = 900000000;
50
51        /**
52         * Construtor da classe JobScheduler
53         * @return object Objeto da classe JobScheduler
54         * @access public
55         */
56        function JobScheduler()
57        {
58                $this->currentDate = new DateTime(date('Y-n-j G:i:00'));
59                $this->db = &$GLOBALS['workflow']['workflowObjects']->getDBGalaxia()->Link_ID;
60                $this->jobManager = &$GLOBALS['workflow']['factory']->getInstance('WorkflowJobManager');
61        }
62
63        /**
64         * Gera um objeto de data (dos Jobs) a partir de um registro de banco de dados
65         * @param array $record Um registro da tabela de jobs
66         * @return object Um objeto de data
67         * @access private
68         */
69        private function convertRecordToDateObject($record)
70        {
71                $interval = array('value' => $record['interval_value'], 'unity' => $record['interval_unity']);
72                $startDate = new DateTime($record['time_start']);
73
74                $object = null;
75                switch ($record['date_type'])
76                {
77                        case DateType::ABSOLUTE_DATE:
78                                $object = new AbsoluteDate($startDate, $interval);
79                                break;
80
81                        case DateType::WEEK_DATE:
82                                $object = new WeekDate($startDate, $interval);
83                                $object->setWeekDays($record['week_days']);
84                                break;
85
86                        case DateType::RELATIVE_DATE:
87                                $object = new RelativeDate($startDate, $interval);
88                                $object->setOffset($record['month_offset']);
89                                break;
90                }
91
92                return $object;
93        }
94
95        /**
96         * Verifica os jobs que devem ser executados e solicita sua execução
97         * @return void
98         * @access public
99         */
100        public function run()
101        {
102                $records = $this->db->query('SELECT job.job_id, job.wf_process_id, job.name, job.time_start, job.interval_value, job.interval_unity, job.date_type, job.week_days, job.month_offset FROM egw_wf_jobs job, egw_wf_processes process WHERE job.active AND (job.wf_process_id = process.wf_p_id) AND (wf_is_active = \'y\')')->getArray();
103                $jobs = array();
104                foreach ($records as $record)
105                        if ($this->convertRecordToDateObject($record)->checkMatchesInterval($this->currentDate))
106                                $jobs[] = $record;
107
108                $runningJobs = array_map(array($this, 'execute'), $jobs);
109
110                $numerOfJobs = count($runningJobs);
111                $timeLeft = JobScheduler::MAXIMUM_EXECUTION_TIME;
112                $timeStep = 50000;
113                do
114                {
115                        $active = false;
116                        for ($i = 0; ($i < $numerOfJobs) && !$active; $i++)
117                                $active = $active || $runningJobs[$i]->isActive();
118                        usleep($timeStep);
119                        $timeLeft -= $timeStep;
120                        if ($timeLeft <= 0)
121                                $active = false;
122                }
123                while ($active);
124
125                for ($i = 0; $i < $numerOfJobs; $i++)
126                {
127                        if (!$runningJobs[$i]->isActive())
128                        {
129                                if (strpos(($errors = $runningJobs[$i]->getError()), 'PHP Fatal error') !== false)
130                                        $this->jobManager->writeLog($jobs[$i]['job_id'], $this->currentDate, $errors, JobManager::STATUS_ERROR);
131                                $runningJobs[$i]->close();
132                        }
133                        else
134                        {
135                                $runningJobs[$i]->kill();
136                                $this->jobManager->writeLog($jobs[$i]['job_id'], $this->currentDate, 'O Job foi abortado por ultrapassar o limite do tempo de execução (atualmente em: ' . (JobScheduler::MAXIMUM_EXECUTION_TIME / 1000000) . 's)', JobManager::STATUS_FAIL);
137                        }
138                }
139        }
140
141        /**
142         * Dispara a execução de um Job
143         * @param array $job Um registro da tabela de jobs
144         * @param bool $testMode Indica se o Job será executado em modo de teste (true) ou não (false)
145         * @return object Um objeto da classe Thread que gerencia a execução do Job
146         * @access public
147         */
148        public function execute($job, $testMode = false)
149        {
150                if (($job['interval_unity'] == DateUnity::NONE) && (!$testMode))
151                {
152                        $disable = true;
153                        if ($job['date_type'] == DateType::WEEK_DATE)
154                                if (WeekDate::getWeekDay($this->currentDate) <= ($job['week_days'] - WeekDate::getWeekDay($this->currentDate)))
155                                        $disable = false;
156
157                        if ($disable)
158                                $records = $this->db->query('UPDATE egw_wf_jobs SET active = FALSE WHERE job_id = ?', array($job['job_id']));
159                }
160
161                $parameters = array();
162                $parameters['file'] = $this->jobManager->getJobFile($job['job_id']);
163                $parameters['jobID'] = $job['job_id'];
164                $parameters['processID'] = $job['wf_process_id'];
165                $parameters['currentDate'] = $this->currentDate->format('Y-m-d H:i:00');
166                $parameters['className'] = $this->jobManager->getClassName($job['job_id']);
167                $parameters['maximumExecutionTime'] = JobScheduler::MAXIMUM_EXECUTION_TIME / 1000000;
168                $parameters['testMode'] = $testMode;
169                $parameters = base64_encode(serialize($parameters));
170
171                $previousDir = getcwd();
172                chdir(GALAXIA_LIBRARY . '/../');
173                $output = $GLOBALS['workflow']['factory']->newInstance('Thread', 'class.JobRunner.inc.php "' . $parameters . '"');
174                chdir($previousDir);
175                return $output;
176        }
177
178        /**
179         * Pega a data atual
180         * @return object A data atual
181         * @access public
182         */
183        public function getCurrentDate()
184        {
185                return $this->currentDate;
186        }
187}
188
189/* se este arquivo é executado a partir da linha de comando, executa os
190 * jobs que estão programados para execução no momento da chamada */
191if (php_sapi_name() == 'cli')
192{
193        require_once 'common.inc.php';
194        $GLOBALS['workflow']['factory']->getInstance('WorkflowMacro')->prepareEnvironment();
195
196        $job = new JobScheduler();
197        $job->run();
198}
199?>
Note: See TracBrowser for help on using the repository browser.