PageRenderTime 28ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/app/code/community/MDN/BackgroundTask/Model/CronObserver.php

https://bitbucket.org/premcgvak/scarlet-changes
PHP | 271 lines | 155 code | 39 blank | 77 comment | 21 complexity | 61b4407ef8c39990aeab8f721f7d1f3d MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /**
  3. * Magento
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * This source file is subject to the Open Software License (OSL 3.0)
  8. * that is bundled with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://opensource.org/licenses/osl-3.0.php
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@magento.com so we can send you a copy immediately.
  14. *
  15. * DISCLAIMER
  16. *
  17. * Do not edit or add to this file if you wish to upgrade Magento to newer
  18. * versions in the future. If you wish to customize Magento for your
  19. * needs please refer to http://www.magento.com for more information.
  20. *
  21. * @category Mage
  22. * @package Mage_Cron
  23. * @copyright Copyright (c) 2006-2014 X.commerce, Inc. (http://www.magento.com)
  24. * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
  25. */
  26. /**
  27. * Crontab observer
  28. *
  29. * @category Mage
  30. * @package Mage_Cron
  31. * @author Magento Core Team <core@magentocommerce.com>
  32. */
  33. class MDN_BackgroundTask_Model_CronObserver extends Mage_Cron_Model_Observer
  34. {
  35. const DEBUG = true;
  36. const DEBUG_LOG_FILE = 'cron_execution.log';
  37. public function cronLog($message){
  38. if(self::DEBUG){
  39. echo '<br/>'.$message;
  40. }else{
  41. Mage::log($message, null, self::DEBUG_LOG_FILE);
  42. }
  43. }
  44. /**
  45. * Process cron queue
  46. * Generate tasks schedule
  47. * Cleanup tasks schedule
  48. *
  49. * @param Varien_Event_Observer $observer
  50. */
  51. public function dispatch($observer)
  52. {
  53. $begin = microtime(true);
  54. $this->cronLog('Begin Cron execution at '.date('Y-m-d H:i:s')."\n");
  55. $schedules = $this->getPendingSchedules();
  56. $this->cronLog('<b>NB task to execute :'.count($schedules).'</b><br/>');
  57. $jobsRoot = Mage::getConfig()->getNode('crontab/jobs');
  58. $defaultJobsRoot = Mage::getConfig()->getNode('default/crontab/jobs');
  59. /** @var $schedule Mage_Cron_Model_Schedule */
  60. foreach ($schedules->getIterator() as $schedule) {
  61. $jobConfig = $jobsRoot->{$schedule->getJobCode()};
  62. $this->cronLog('LOAD task #'.$schedule->getschedule_id().' : <b>'.$schedule->getjob_code().'</b> scheduled at '.$schedule->getScheduledAt());
  63. if (!$jobConfig || !$jobConfig->run) {
  64. $jobConfig = $defaultJobsRoot->{$schedule->getJobCode()};
  65. if (!$jobConfig || !$jobConfig->run) {
  66. continue;
  67. }
  68. }
  69. $this->_processJob($schedule, $jobConfig);
  70. }
  71. $this->generate();
  72. $this->cleanup();
  73. $end = microtime(true);
  74. $duration = ($end - $begin);
  75. $this->cronLog('<b>End Cron execution at '.date('Y-m-d H:i:s').' in '.$duration.'s </b><br/>');
  76. }
  77. /**
  78. * Generate cron schedule
  79. *
  80. * @return Mage_Cron_Model_Observer
  81. */
  82. public function generate()
  83. {
  84. $this->cronLog('<br>Begin GENERATING NEXT TASKS at '.date('Y-m-d H:i:s'));
  85. /**
  86. * check if schedule generation is needed
  87. */
  88. $lastRun = Mage::app()->loadCache(self::CACHE_KEY_LAST_SCHEDULE_GENERATE_AT);
  89. if ($lastRun > time() - Mage::getStoreConfig(self::XML_PATH_SCHEDULE_GENERATE_EVERY)*60) {
  90. $this->cronLog('SKIP GENERATING NEXT TASKS at '.date('Y-m-d H:i:s').'<br/>');
  91. return $this;
  92. }
  93. $schedules = $this->getPendingSchedules();
  94. $exists = array();
  95. foreach ($schedules->getIterator() as $schedule) {
  96. $exists[$schedule->getJobCode().'/'.$schedule->getScheduledAt()] = 1;
  97. }
  98. /**
  99. * generate global crontab jobs
  100. */
  101. $config = Mage::getConfig()->getNode('crontab/jobs');
  102. if ($config instanceof Mage_Core_Model_Config_Element) {
  103. $this->_generateJobs($config->children(), $exists);
  104. }
  105. /**
  106. * generate configurable crontab jobs
  107. */
  108. $config = Mage::getConfig()->getNode('default/crontab/jobs');
  109. if ($config instanceof Mage_Core_Model_Config_Element) {
  110. $this->_generateJobs($config->children(), $exists);
  111. }
  112. /**
  113. * save time schedules generation was ran with no expiration
  114. */
  115. Mage::app()->saveCache(time(), self::CACHE_KEY_LAST_SCHEDULE_GENERATE_AT, array('crontab'), null);
  116. $this->cronLog('End GENERATING NEXT TASKS at '.date('Y-m-d H:i:s').'<br/>');
  117. return $this;
  118. }
  119. /**
  120. * Clean up the history of tasks
  121. *
  122. * @return Mage_Cron_Model_Observer
  123. */
  124. public function cleanup()
  125. {
  126. $this->cronLog('<br>Begin CLEANING TASKS at '.date('Y-m-d H:i:s'));
  127. // check if history cleanup is needed
  128. $lastCleanup = Mage::app()->loadCache(self::CACHE_KEY_LAST_HISTORY_CLEANUP_AT);
  129. if ($lastCleanup > time() - Mage::getStoreConfig(self::XML_PATH_HISTORY_CLEANUP_EVERY)*60) {
  130. $this->cronLog('SKIP CLEANING TASKS at '.date('Y-m-d H:i:s').'<br/>');
  131. return $this;
  132. }
  133. $history = Mage::getModel('cron/schedule')->getCollection()
  134. ->addFieldToFilter('status', array('in'=>array(
  135. Mage_Cron_Model_Schedule::STATUS_SUCCESS,
  136. Mage_Cron_Model_Schedule::STATUS_MISSED,
  137. Mage_Cron_Model_Schedule::STATUS_ERROR,
  138. )))
  139. ->load();
  140. $historyLifetimes = array(
  141. Mage_Cron_Model_Schedule::STATUS_SUCCESS => Mage::getStoreConfig(self::XML_PATH_HISTORY_SUCCESS)*60,
  142. Mage_Cron_Model_Schedule::STATUS_MISSED => Mage::getStoreConfig(self::XML_PATH_HISTORY_FAILURE)*60,
  143. Mage_Cron_Model_Schedule::STATUS_ERROR => Mage::getStoreConfig(self::XML_PATH_HISTORY_FAILURE)*60,
  144. );
  145. $now = time();
  146. foreach ($history->getIterator() as $record) {
  147. if (strtotime($record->getExecutedAt()) < $now-$historyLifetimes[$record->getStatus()]) {
  148. $record->delete();
  149. }
  150. }
  151. // save time history cleanup was ran with no expiration
  152. Mage::app()->saveCache(time(), self::CACHE_KEY_LAST_HISTORY_CLEANUP_AT, array('crontab'), null);
  153. $this->cronLog('End CLEANING TASKS at '.date('Y-m-d H:i:s').'<br/>');
  154. return $this;
  155. }
  156. /**
  157. * Process cron task
  158. *
  159. * @param Mage_Cron_Model_Schedule $schedule
  160. * @param $jobConfig
  161. * @param bool $isAlways
  162. * @return Mage_Cron_Model_Observer
  163. */
  164. protected function _processJob($schedule, $jobConfig, $isAlways = false)
  165. {
  166. // $this->cronLog('BEGIN processJob task #'.$schedule->getschedule_id().' : <b>'.$schedule->getjob_code().'</b> at '.date('Y-m-d H:i:s'));
  167. $runConfig = $jobConfig->run;
  168. if (!$isAlways) {
  169. $scheduleLifetime = Mage::getStoreConfig(self::XML_PATH_SCHEDULE_LIFETIME) * 60;
  170. $now = time();
  171. $time = strtotime($schedule->getScheduledAt());
  172. if ($time > $now) {
  173. $this->cronLog(' -> SKIP task #'.$schedule->getschedule_id().' : <b>'.$schedule->getjob_code().'</b><br/>');
  174. return;
  175. }
  176. }
  177. $errorStatus = Mage_Cron_Model_Schedule::STATUS_ERROR;
  178. try {
  179. if (!$isAlways) {
  180. if ($time < $now - $scheduleLifetime) {
  181. $errorStatus = Mage_Cron_Model_Schedule::STATUS_MISSED;
  182. $this->cronLog(Mage::helper('cron')->__('Too late for the schedule.'));
  183. Mage::throwException(Mage::helper('cron')->__('Too late for the schedule.'));
  184. }
  185. }
  186. if ($runConfig->model) {
  187. if (!preg_match(self::REGEX_RUN_MODEL, (string)$runConfig->model, $run)) {
  188. $this->cronLog(Mage::helper('cron')->__('Invalid model/method definition, expecting "model/class::method".'));
  189. Mage::throwException(Mage::helper('cron')->__('Invalid model/method definition, expecting "model/class::method".'));
  190. }
  191. if (!($model = Mage::getModel($run[1])) || !method_exists($model, $run[2])) {
  192. $this->cronLog(Mage::helper('cron')->__('Invalid callback: %s::%s does not exist', $run[1], $run[2]));
  193. Mage::throwException(Mage::helper('cron')->__('Invalid callback: %s::%s does not exist', $run[1], $run[2]));
  194. }
  195. $callback = array($model, $run[2]);
  196. $arguments = array($schedule);
  197. }
  198. if (empty($callback)) {
  199. $this->cronLog(Mage::helper('cron')->__('No callbacks found'));
  200. Mage::throwException(Mage::helper('cron')->__('No callbacks found'));
  201. }
  202. if (!$isAlways) {
  203. if (!$schedule->tryLockJob()) {
  204. $this->cronLog('SKIP task #'.$schedule->getschedule_id().' : <b>'.$schedule->getjob_code().'</b> at '.date('Y-m-d H:i:s').'<br/>');
  205. // another cron started this job intermittently, so skip it
  206. return;
  207. }
  208. /**
  209. though running status is set in tryLockJob we must set it here because the object
  210. was loaded with a pending status and will set it back to pending if we don't set it here
  211. */
  212. }
  213. $begin = microtime(true);
  214. $this->cronLog('EXEC task #'.$schedule->getschedule_id().' : <b>'.$schedule->getjob_code().'</b> at '.date('Y-m-d H:i:s'));
  215. $schedule
  216. ->setExecutedAt(strftime('%Y-%m-%d %H:%M:%S', time()))
  217. ->save();
  218. call_user_func_array($callback, $arguments);
  219. $schedule
  220. ->setStatus(Mage_Cron_Model_Schedule::STATUS_SUCCESS)
  221. ->setFinishedAt(strftime('%Y-%m-%d %H:%M:%S', time()));
  222. $end = microtime(true);
  223. $duration = ($end - $begin);
  224. $this->cronLog('<b>END task #'.$schedule->getschedule_id().' : '.$schedule->getjob_code().' in '.$duration.'s </b><br/>');
  225. } catch (Exception $e) {
  226. $schedule->setStatus($errorStatus)
  227. ->setMessages($e->__toString());
  228. }
  229. $schedule->save();
  230. return $this;
  231. }
  232. }