2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4 * SugarCRM Community Edition is a customer relationship management program developed by
5 * SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
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.
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
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
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.
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.
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 ********************************************************************************/
39 require_once 'modules/SchedulersJobs/SchedulersJob.php';
48 * Max number of failures for job
53 * Job running timeout - longer than that, job is failed by force
56 public $timeout = 86400; // 24 hours
59 * Table in the DB that stores jobs
62 protected $job_queue_table;
70 public function __construct()
72 $this->db = DBManagerFactory::getInstance();
73 $job = new SchedulersJob();
74 $this->job_queue_table = $job->table_name;
75 if(!empty($GLOBALS['sugar_config']['jobs']['max_retries'])) {
76 $this->jobTries = $GLOBALS['sugar_config']['jobs']['max_retries'];
78 if(!empty($GLOBALS['sugar_config']['jobs']['timeout'])) {
79 $this->timeout = $GLOBALS['sugar_config']['jobs']['timeout'];
84 * Submit a new job to the queue
85 * @param SugarJob $job
86 * @param User $user User to run the job under
88 public function submitJob($job)
90 $job->id = create_guid();
91 $job->new_with_id = true;
92 $job->status = SchedulersJob::JOB_STATUS_QUEUED;
93 $job->resolution = SchedulersJob::JOB_PENDING;
94 if(empty($job->execute_time)) {
95 $job->execute_time = $GLOBALS['timedate']->nowDb();
103 * Get Job object by ID
104 * @param string $jobId
107 protected function getJob($jobId)
109 $job = new SchedulersJob();
110 $job->retrieve($jobId);
111 if(empty($job->id)) {
112 $GLOBALS['log']->info("Job $jobId not found!");
119 * Resolve job as success or failure
120 * @param string $jobId
121 * @param string $resolution One of JOB_ constants that define job status
122 * @param string $message
125 public function resolveJob($jobId, $resolution, $message = null)
127 $job = $this->getJob($jobId);
128 if(empty($job)) return false;
129 return $job->resolveJob($resolution, $message);
133 * Rerun this job again
134 * @param string $jobId
135 * @param string $message
136 * @param string $delay how long to delay (default is job's delay)
139 public function postponeJob($jobId, $message = null, $delay = null)
141 $job = $this->getJob($jobId);
142 if(empty($job)) return false;
143 return $job->postponeJob($message, $delay);
148 * @param string $jobId
150 public function deleteJob($jobId)
152 $job = new SchedulersJob();
153 if(empty($job)) return false;
154 return $job->mark_deleted($jobId);
158 * Remove old jobs that still are marked as running
159 * @return bool true if no failed job discovered, false if some job were failed
161 public function cleanup()
163 // fail jobs that are too old
165 // bsitnikovski@sugarcrm.com bugfix #56144: Scheduler Bug
166 $date = $this->db->convert($this->db->quoted($GLOBALS['timedate']->getNow()->modify("-{$this->timeout} seconds")->asDb()), 'datetime');
167 $res = $this->db->query("SELECT id FROM {$this->job_queue_table} WHERE status='".SchedulersJob::JOB_STATUS_RUNNING."' AND date_modified <= $date");
168 while($row = $this->db->fetchByAssoc($res)) {
169 $this->resolveJob($row["id"], SchedulersJob::JOB_FAILURE, translate('ERR_TIMEOUT', 'SchedulersJobs'));
172 // TODO: soft-delete old done jobs?
177 * Nuke all jobs from the queue
179 public function cleanQueue()
181 $this->db->query("DELETE FROM {$this->job_queue_table}");
185 * Fetch the next job in the queue and mark it running
186 * @param string $clientID ID of the client requesting the job
189 public function nextJob($clientID)
191 $now = $this->db->now();
192 $queued = SchedulersJob::JOB_STATUS_QUEUED;
193 $try = $this->jobTries;
195 // TODO: tranaction start?
196 $id = $this->db->getOne("SELECT id FROM {$this->job_queue_table} WHERE execute_time <= $now AND status = '$queued' ORDER BY date_entered ASC");
200 $job = new SchedulersJob();
202 if(empty($job->id)) {
205 $job->status = SchedulersJob::JOB_STATUS_RUNNING;
206 $job->client = $clientID;
207 $client = $this->db->quote($clientID);
208 // using direct query here to be able to fetch affected count
209 // if count is 0 this means somebody changed the job status and we have to try again
210 $res = $this->db->query("UPDATE {$this->job_queue_table} SET status='{$job->status}', date_modified=$now, client='$client' WHERE id='{$job->id}' AND status='$queued'");
211 if($this->db->getAffectedRowCount($res) == 0) {
212 // somebody stole our job, try again
215 // to update dates & possible hooks
219 // TODO: commit/check?
225 * Run schedulers to instantiate scheduled jobs
227 public function runSchedulers()
229 $sched = new Scheduler();
230 $sched->checkPendingJobs($this);