source: branches/2.2/workflow/inc/class.JobScheduler.inc.php @ 3167

Revision 3167, 6.3 KB checked in by viani, 14 years ago (diff)

Ticket #1135 - Merged r1990:3166 from /trunk/workflow into /branches/2.2/workflow

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