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 | |
---|
12 | require_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 | */ |
---|
22 | class 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::newInstance('AbsoluteDate', $startDate, $interval); |
---|
76 | break; |
---|
77 | |
---|
78 | case DateType::WEEK_DATE: |
---|
79 | $object = &Factory::newInstance('WeekDate', $startDate, $interval); |
---|
80 | $object->setWeekDays($record['week_days']); |
---|
81 | break; |
---|
82 | |
---|
83 | case DateType::RELATIVE_DATE: |
---|
84 | $object = &Factory::newInstance('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 | if(!empty($job['parameters'])) |
---|
167 | $parameters['jobParams'] = $job['parameters']; |
---|
168 | |
---|
169 | $parameters = base64_encode(serialize($parameters)); |
---|
170 | |
---|
171 | $previousDir = getcwd(); |
---|
172 | chdir(GALAXIA_LIBRARY . '/../'); |
---|
173 | $output = 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 */ |
---|
191 | if (php_sapi_name() == 'cli') |
---|
192 | { |
---|
193 | require_once 'common.inc.php'; |
---|
194 | Factory::getInstance('WorkflowMacro')->prepareEnvironment(); |
---|
195 | |
---|
196 | $job = Factory::newInstance('JobScheduler'); |
---|
197 | $job->run(); |
---|
198 | } |
---|
199 | ?> |
---|