Version Notes
ACL issue fix
Download this release
Release Info
Developer | Arron Moss |
Extension | Zero1_Crondoctor |
Version | 1.0.10 |
Comparing to | |
See all releases |
Code changes from version 1.0.6 to 1.0.10
- app/code/community/Zero1/Crondoctor/Block/Adminhtml/Visual.php +11 -0
- app/code/community/Zero1/Crondoctor/Block/Adminhtml/Visual/Form.php +125 -0
- app/code/community/Zero1/Crondoctor/Block/Adminhtml/Visual/Lag.php +54 -0
- app/code/community/Zero1/Crondoctor/Block/Adminhtml/Visual/Visual.php +179 -0
- app/code/community/Zero1/Crondoctor/Model/Observer.php +220 -47
- app/code/community/Zero1/Crondoctor/Model/Observer/Zombie.php +66 -0
- app/code/community/Zero1/Crondoctor/Model/Schedule.php +9 -0
- app/code/community/Zero1/Crondoctor/Model/Schedule/Job.php +182 -0
- app/code/community/Zero1/Crondoctor/Model/Schedule/Job/Process.php +52 -0
- app/code/community/Zero1/Crondoctor/Model/Visual/Schedule.php +102 -0
- app/code/community/Zero1/Crondoctor/Model/Visual/Schedule/Job.php +182 -0
- app/code/community/Zero1/Crondoctor/Model/Visual/Schedule/Job/Process.php +54 -0
- app/code/community/Zero1/Crondoctor/README.md +59 -0
- app/code/community/Zero1/Crondoctor/controllers/Adminhtml/Crondoctor/VisualController.php +65 -0
- app/code/community/Zero1/Crondoctor/controllers/Adminhtml/CrondoctorController.php +5 -0
- app/code/community/Zero1/Crondoctor/etc/adminhtml.xml +12 -0
- app/code/community/Zero1/Crondoctor/etc/config.xml +34 -7
- app/code/community/Zero1/Crondoctor/etc/system.xml +19 -0
- app/code/community/Zero1/Crondoctor/sql/zero1_crondoctor_setup/upgrade-1.0.7-1.0.8.php +19 -0
- app/code/community/Zero1/Crondoctor/sql/zero1_crondoctor_setup/upgrade-1.0.8-1.0.9.php +16 -0
- app/design/adminhtml/default/default/layout/crondoctor/crondoctor.xml +6 -0
- app/design/adminhtml/default/default/template/crondoctor/visual/container.phtml +14 -0
- app/design/adminhtml/default/default/template/crondoctor/visual/visual.phtml +81 -0
- package.xml +5 -5
- zero1/cron.php +95 -0
- zero1/cron.sh +28 -0
app/code/community/Zero1/Crondoctor/Block/Adminhtml/Visual.php
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
class Zero1_Crondoctor_Block_Adminhtml_Visual extends Mage_Adminhtml_Block_Widget_Container
|
3 |
+
{
|
4 |
+
protected $_template = 'crondoctor/visual/container.phtml';
|
5 |
+
protected $_headerText = 'Cron Doctor Jobs Visual';
|
6 |
+
|
7 |
+
public function getFormHtml(){
|
8 |
+
return $this->getLayout()->createBlock('zero1_crondoctor/adminhtml_visual_form')->toHtml();
|
9 |
+
}
|
10 |
+
|
11 |
+
}
|
app/code/community/Zero1/Crondoctor/Block/Adminhtml/Visual/Form.php
ADDED
@@ -0,0 +1,125 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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@magentocommerce.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.magentocommerce.com for more information.
|
20 |
+
*
|
21 |
+
* @category Mage
|
22 |
+
* @package Mage_Adminhtml
|
23 |
+
* @copyright Copyright (c) 2013 Magento Inc. (http://www.magentocommerce.com)
|
24 |
+
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
|
25 |
+
*/
|
26 |
+
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Sitemap edit form
|
30 |
+
*
|
31 |
+
* @category Mage
|
32 |
+
* @package Mage_Adminhtml
|
33 |
+
* @author Magento Core Team <core@magentocommerce.com>
|
34 |
+
*/
|
35 |
+
class Zero1_Crondoctor_Block_Adminhtml_Visual_Form extends Mage_Adminhtml_Block_Widget_Form
|
36 |
+
{
|
37 |
+
/**
|
38 |
+
* Init form
|
39 |
+
*/
|
40 |
+
public function __construct()
|
41 |
+
{
|
42 |
+
parent::__construct();
|
43 |
+
$this->setId('redirection_form');
|
44 |
+
$this->setTitle(Mage::helper('adminhtml')->__('Redirection Information'));
|
45 |
+
}
|
46 |
+
|
47 |
+
|
48 |
+
protected function _prepareForm()
|
49 |
+
{
|
50 |
+
$model = new Varien_Object();
|
51 |
+
|
52 |
+
$form = new Varien_Data_Form(array(
|
53 |
+
'id' => 'visual_form',
|
54 |
+
'action' => $this->getData('action'),
|
55 |
+
'method' => 'post'
|
56 |
+
));
|
57 |
+
|
58 |
+
$fieldset = $form->addFieldset(
|
59 |
+
'crondoctor_visual_form',
|
60 |
+
array('legend' => Mage::helper('adminhtml')->__('Options')));
|
61 |
+
|
62 |
+
|
63 |
+
$fieldset->addField('from', 'text', array(
|
64 |
+
'label' => Mage::helper('adminhtml')->__('From'),
|
65 |
+
'name' => 'from',
|
66 |
+
'required' => true,
|
67 |
+
'note' => Mage::helper('adminhtml')->__('number of hours from now (accepts -ve and +ve'),
|
68 |
+
));
|
69 |
+
|
70 |
+
$fieldset->addField('to', 'text', array(
|
71 |
+
'label' => Mage::helper('adminhtml')->__('To'),
|
72 |
+
'name' => 'to',
|
73 |
+
'required' => true,
|
74 |
+
'note' => Mage::helper('adminhtml')->__('number of hours from now (accepts -ve and +ve'),
|
75 |
+
));
|
76 |
+
|
77 |
+
$fieldset->addField('visual_type', 'select', array(
|
78 |
+
'label' => Mage::helper('adminhtml')->__('Visual Type'),
|
79 |
+
'name' => 'visual_type',
|
80 |
+
'required' => true,
|
81 |
+
'values' => array(
|
82 |
+
'stats' => Mage::helper('adminhtml')->__('Stats'),
|
83 |
+
'lag' => Mage::helper('adminhtml')->__('Lag'),
|
84 |
+
),
|
85 |
+
));
|
86 |
+
|
87 |
+
$fieldset->addField('order_by', 'select', array(
|
88 |
+
'label' => Mage::helper('adminhtml')->__('Order By'),
|
89 |
+
'name' => 'order_by',
|
90 |
+
'required' => true,
|
91 |
+
'values' => array(
|
92 |
+
'expected_runs' => Mage::helper('adminhtml')->__('Expected Runs'),
|
93 |
+
),
|
94 |
+
));
|
95 |
+
|
96 |
+
$fieldset->addField('submit', 'button', array(
|
97 |
+
'label' => Mage::helper('adminhtml')->__(''),
|
98 |
+
'name' => Mage::helper('adminhtml')->__('aaa'),
|
99 |
+
'class' => 'save',
|
100 |
+
'onclick' => '
|
101 |
+
new Ajax.Request(\''.Mage::helper('adminhtml')->getUrl('adminhtml/crondoctor_visual/ajax').'\',
|
102 |
+
{
|
103 |
+
method: \'get\',
|
104 |
+
parameters: Form.serialize(\'visual_form\'),
|
105 |
+
onSuccess: function(transport){
|
106 |
+
$(\'visual-container\').update(transport.responseText);
|
107 |
+
}
|
108 |
+
});'
|
109 |
+
));
|
110 |
+
|
111 |
+
$form->setValues(array('submit' => 'Submit'));
|
112 |
+
$form->setUseContainer(true);
|
113 |
+
$this->setForm($form);
|
114 |
+
|
115 |
+
$this->setChild('form_after', $this->getLayout()->createBlock('adminhtml/widget_form_element_dependence')
|
116 |
+
->addFieldMap('visual_type', 'visual_type')
|
117 |
+
->addFieldMap('order_by', 'order_by')
|
118 |
+
->addFieldDependence('order_by', 'visual_type', 'stats')
|
119 |
+
);
|
120 |
+
|
121 |
+
|
122 |
+
return parent::_prepareForm();
|
123 |
+
}
|
124 |
+
|
125 |
+
}
|
app/code/community/Zero1/Crondoctor/Block/Adminhtml/Visual/Lag.php
ADDED
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
class Zero1_Crondoctor_Block_Adminhtml_Visual_Lag extends Mage_Core_Block_Template{
|
3 |
+
|
4 |
+
protected $_template = 'crondoctor/visual/lag.phtml';
|
5 |
+
|
6 |
+
public function getLagData(){
|
7 |
+
$cronCollection = Mage::getModel('cron/schedule')->getCollection();
|
8 |
+
$cronCollection->addFieldToFilter('executed_at', array('gteq' => strftime('%Y-%m-%d %H:%M:%S', $this->getFrom())));
|
9 |
+
$cronCollection->addFieldToFilter('executed_at', array('lteq' => strftime('%Y-%m-%d %H:%M:%S', $this->getTo())));
|
10 |
+
$cronCollection->addFieldToFilter('job_code', array('nin' => array('enterprise_refresh_index')));
|
11 |
+
|
12 |
+
|
13 |
+
// return $cronCollection->getSelectSql(true);
|
14 |
+
if(!$cronCollection->count()){
|
15 |
+
return array();
|
16 |
+
}
|
17 |
+
|
18 |
+
$data = array();
|
19 |
+
$values = array(); //used to calc rolling average
|
20 |
+
|
21 |
+
/* @var $cronJob Mage_Cron_Model_Schedule */
|
22 |
+
foreach($cronCollection as $cronJob){
|
23 |
+
|
24 |
+
$hour = date('H', strtotime($cronJob->getExecutedAt()));
|
25 |
+
$dayOfYear = date('z', strtotime($cronJob->getExecutedAt()));
|
26 |
+
$lag = (strtotime($cronJob->getExecutedAt()) - strtotime($cronJob->getScheduledAt()));
|
27 |
+
|
28 |
+
if(!isset($data[$dayOfYear.'-'.$hour])){
|
29 |
+
$data[$dayOfYear.'-'.$hour] = array();
|
30 |
+
}
|
31 |
+
$values[] = $lag;
|
32 |
+
if(count($values) > 10){
|
33 |
+
array_shift($values);
|
34 |
+
}
|
35 |
+
|
36 |
+
$avg = array_sum($values) / count($values);
|
37 |
+
$executionTime = strtotime($cronJob->getFinishedAt()) - strtotime($cronJob->getExecutedAt());
|
38 |
+
|
39 |
+
$data[$dayOfYear.'-'.$hour][] =
|
40 |
+
array(
|
41 |
+
'code' => $cronJob->getJobCode(),
|
42 |
+
'lag' => $lag,
|
43 |
+
'avg' => $avg,
|
44 |
+
'details' => array(
|
45 |
+
'job code' => $cronJob->getJobCode(),
|
46 |
+
'lag' => floor($lag/ 3600).':'. floor($lag%3600 / 60),
|
47 |
+
'execution time' => floor($executionTime/ 3600).':'. floor($executionTime%3600 / 60),
|
48 |
+
),
|
49 |
+
);
|
50 |
+
}
|
51 |
+
|
52 |
+
return $data;
|
53 |
+
}
|
54 |
+
}
|
app/code/community/Zero1/Crondoctor/Block/Adminhtml/Visual/Visual.php
ADDED
@@ -0,0 +1,179 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
class Zero1_Crondoctor_Block_Adminhtml_Visual_Visual extends Mage_Core_Block_Template{
|
3 |
+
|
4 |
+
|
5 |
+
protected $_template = 'crondoctor/visual/visual.phtml';
|
6 |
+
private $schedule = null;
|
7 |
+
|
8 |
+
public function _construct(){
|
9 |
+
$this->setMinumMinDisplayWidth(12);
|
10 |
+
}
|
11 |
+
|
12 |
+
/* @return Zero1_Crondoctor_Model_Schedule */
|
13 |
+
public function getSchedule(){
|
14 |
+
if($this->schedule === null){
|
15 |
+
$schedule = Mage::getModel('zero1_crondoctor/visual_schedule', array(
|
16 |
+
'until' => $this->getTo(),
|
17 |
+
'from' => $this->getFrom(),
|
18 |
+
));
|
19 |
+
|
20 |
+
$schedule->orderBy($this->getOrderBy());
|
21 |
+
$this->schedule = $schedule;
|
22 |
+
}
|
23 |
+
return $this->schedule;
|
24 |
+
}
|
25 |
+
|
26 |
+
public function getJobHtml(Zero1_Crondoctor_Model_Schedule_Job $job, $from, $width){
|
27 |
+
|
28 |
+
$jobDepthInfo = array();
|
29 |
+
$jobHeight = 10;
|
30 |
+
$jobProccessHtml = '';
|
31 |
+
$html = '';
|
32 |
+
|
33 |
+
foreach($job->getProcesses() as $timestamp => $process){
|
34 |
+
|
35 |
+
if(!empty($jobDepthInfo)){
|
36 |
+
$depthFound = false;
|
37 |
+
|
38 |
+
$minValue = $this->getLowestSetValue($process);
|
39 |
+
|
40 |
+
foreach($jobDepthInfo as $depth => $maxValue){
|
41 |
+
if($minValue > $maxValue){
|
42 |
+
$depthFound = true;
|
43 |
+
break;
|
44 |
+
}
|
45 |
+
}
|
46 |
+
|
47 |
+
if(!$depthFound){
|
48 |
+
$jobDepth = count($jobDepthInfo);
|
49 |
+
}else{
|
50 |
+
$jobDepth = $depth;
|
51 |
+
}
|
52 |
+
}else{
|
53 |
+
$jobDepth = 0;
|
54 |
+
}
|
55 |
+
|
56 |
+
$jobProccessHtml .= $this->getJobProcessHtml($process, $jobDepth, $jobHeight, $from);
|
57 |
+
|
58 |
+
$jobDepthInfo[$jobDepth] = max(
|
59 |
+
$process->getExecutedAt(),
|
60 |
+
$process->getScheduledAt(),
|
61 |
+
$process->getFinishedAt(),
|
62 |
+
$process->getCreatedAt()
|
63 |
+
);
|
64 |
+
|
65 |
+
}
|
66 |
+
|
67 |
+
$html .= '<div style="width: '.$width.'px; height: '.(max(count($jobDepthInfo), 4) * $jobHeight).'px; ';
|
68 |
+
$html .= ' border-bottom: solid #000000 2px; background-color: #cccccc; position: relative;">';
|
69 |
+
$html .= $jobProccessHtml;
|
70 |
+
$html .= '<div style="clear: both;"></div></div>';
|
71 |
+
|
72 |
+
return array($html, max(count($jobDepthInfo), 4));
|
73 |
+
}
|
74 |
+
|
75 |
+
public function getLowestSetValue(Zero1_Crondoctor_Model_Schedule_Job_Process $process){
|
76 |
+
$values = array();
|
77 |
+
if($process->getCreatedAt()){
|
78 |
+
$values[] = $process->getCreatedAt();
|
79 |
+
}
|
80 |
+
if($process->getUpdatedAt()){
|
81 |
+
$values[] = $process->getUpdatedAt();
|
82 |
+
}
|
83 |
+
if($process->getScheduledAt()){
|
84 |
+
$values[] = $process->getScheduledAt();
|
85 |
+
}
|
86 |
+
if($process->getExecutedAt()){
|
87 |
+
$values[] = $process->getExecutedAt();
|
88 |
+
}
|
89 |
+
if($process->getFinishedAt()){
|
90 |
+
$values[] = $process->getFinishedAt();
|
91 |
+
}
|
92 |
+
return min($values);
|
93 |
+
}
|
94 |
+
|
95 |
+
public function getJobProcessHtml(Zero1_Crondoctor_Model_Visual_Schedule_Job_Process $process, $jobDepth, $jobHeight, $from){
|
96 |
+
|
97 |
+
$html = '<div id="schedule-id-'.$process->getScheduleId().'">';
|
98 |
+
|
99 |
+
if($process->getCreatedAt()){
|
100 |
+
//time from when it was created, to the time it is scheduled to start
|
101 |
+
$html .= $this->createBlock($jobDepth, $jobHeight, $from, $process->getCreatedAt(), $process->getScheduledAt(), 'yellow');
|
102 |
+
if($process->getExecutedAt()){
|
103 |
+
//time from when it should have started to the time it actually did start
|
104 |
+
$html .= $this->createBlock($jobDepth, $jobHeight, $from, $process->getScheduledAt(), $process->getExecutedAt(), 'orange');
|
105 |
+
if($process->getFinishedAt()){
|
106 |
+
//job ran good, show execution time
|
107 |
+
$html .= $this->createBlock($jobDepth, $jobHeight, $from, $process->getExecutedAt(), $process->getFinishedAt(), 'green');
|
108 |
+
}else{
|
109 |
+
//job error'd
|
110 |
+
$html .= $this->createBlock($jobDepth, $jobHeight, $from, $process->getExecutedAt(), $process->getFinishedAt(), 'pink');
|
111 |
+
}
|
112 |
+
}else{
|
113 |
+
//job missed
|
114 |
+
$html .= $this->createBlock($jobDepth, $jobHeight, $from, $process->getScheduledAt(), $process->getUpdatedAt(), 'orange');
|
115 |
+
|
116 |
+
if($process->getStatus() == Mage_Cron_Model_Schedule::STATUS_MISSED){
|
117 |
+
$html .= $this->createBlock($jobDepth, $jobHeight, $from, $process->getUpdatedAt(), $process->getUpdatedAt(), 'red');
|
118 |
+
}
|
119 |
+
}
|
120 |
+
}else{
|
121 |
+
//job never got scheduled
|
122 |
+
$html .= $this->createBlock($jobDepth, $jobHeight, $from, $process->getScheduledAt(), $process->getExecutedAt(), 'black');
|
123 |
+
}
|
124 |
+
|
125 |
+
//add in data for later
|
126 |
+
$html .= '<div style="display: none;">';
|
127 |
+
$html .= 'status:'.$process->getStatus().'<br />';
|
128 |
+
$html .= 'schedule id: '.$process->getScheduledId().'<br />';
|
129 |
+
$html .= 'created at: '.strftime('%Y-%m-%d %H:%M', $process->getCreatedAt()).'<br />';
|
130 |
+
$html .= 'scheduled at: '.strftime('%Y-%m-%d %H:%M', $process->getScheduledAt()).'<br />';
|
131 |
+
$html .= 'executed at: '.strftime('%Y-%m-%d %H:%M:%S', $process->getExecutedAt()).'<br />';
|
132 |
+
$html .= 'finished at: '.strftime('%Y-%m-%d %H:%M:%S', $process->getFinishedAt()).'<br />';
|
133 |
+
$html .= 'updated at: '.strftime('%Y-%m-%d %H:%M:%S', $process->getUpdatedAt()).'<br />';
|
134 |
+
$html .= '</div>';
|
135 |
+
|
136 |
+
$html .= '</div>';
|
137 |
+
|
138 |
+
return $html;
|
139 |
+
}
|
140 |
+
|
141 |
+
public function createBlock($jobDepth, $jobHeight, $from, $startTime, $endTime, $colour){
|
142 |
+
|
143 |
+
$minMinuteDisplayWith = $this->getMinumMinDisplayWidth();
|
144 |
+
if(!$startTime){
|
145 |
+
return '';
|
146 |
+
}
|
147 |
+
|
148 |
+
$top = ($jobDepth * $jobHeight);
|
149 |
+
|
150 |
+
if($from > $startTime){
|
151 |
+
$left = 0;
|
152 |
+
}else{
|
153 |
+
$left =(((($startTime - $from)/60)*$minMinuteDisplayWith) + 20);
|
154 |
+
}
|
155 |
+
|
156 |
+
if(!$endTime){
|
157 |
+
$width = 2;
|
158 |
+
}else{
|
159 |
+
if($from > $startTime){
|
160 |
+
$width = max((((($endTime - $from)/60)*$minMinuteDisplayWith)+20), 2);
|
161 |
+
}else{
|
162 |
+
$width = max(((($endTime - $startTime)/60)*$minMinuteDisplayWith), 2);
|
163 |
+
}
|
164 |
+
}
|
165 |
+
|
166 |
+
$html = '<div ';
|
167 |
+
$html .= 'style="position: absolute; ';
|
168 |
+
$html .= 'height: '.$jobHeight.'px; ';
|
169 |
+
$html .= 'top: '.$top.'px; ';
|
170 |
+
$html .= 'left: '.$left.'px; ';
|
171 |
+
$html .= 'background-color: '.$colour.'; ';
|
172 |
+
$html .= 'width: '.$width.'px; ';
|
173 |
+
$html .= '"></div>';
|
174 |
+
|
175 |
+
return $html;
|
176 |
+
}
|
177 |
+
|
178 |
+
|
179 |
+
}
|
app/code/community/Zero1/Crondoctor/Model/Observer.php
CHANGED
@@ -1,72 +1,151 @@
|
|
1 |
<?php
|
2 |
class Zero1_Crondoctor_Model_Observer extends Mage_Cron_Model_Observer
|
3 |
{
|
4 |
-
const XML_PATH_ZOMBIE_EMAIL_TEMPLATE = 'zero1_crondoctor/settings/zombie_email_template';
|
5 |
-
const XML_PATH_ZOMBIE_EMAIL_TO = 'zero1_crondoctor/settings/zombie_email';
|
6 |
-
const XML_PATH_ZOMBIE_TIME = 'zero1_crondoctor/settings/zombie_time';
|
7 |
-
|
8 |
const XML_PATH_DEVELOPER_MODE = 'zero1_crondoctor/settings/developer_mode';
|
9 |
const XML_PATH_DEVELOPER_MODE_JOBS = 'zero1_crondoctor/settings/developer_mode_jobs';
|
|
|
10 |
|
11 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
|
13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
{
|
15 |
-
$
|
16 |
-
$
|
|
|
17 |
|
18 |
-
|
19 |
-
return; // No destination address.
|
20 |
-
}
|
21 |
|
22 |
-
$
|
23 |
-
$
|
24 |
-
|
25 |
-
|
|
|
26 |
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
|
|
|
|
31 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
|
33 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
|
35 |
-
|
36 |
-
|
37 |
-
|
|
|
|
|
|
|
38 |
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
}
|
|
|
43 |
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
->sendTransactional(
|
51 |
-
Mage::getStoreConfig(self::XML_PATH_ZOMBIE_EMAIL_TEMPLATE, $storeId),
|
52 |
-
Mage::getStoreConfig(Mage_Sales_Model_Order::XML_PATH_EMAIL_IDENTITY, $storeId),
|
53 |
-
$to,
|
54 |
-
null,
|
55 |
-
array(
|
56 |
-
'subject' => $this->_zombieEmailSubject,
|
57 |
-
'job_list_content' => $job_list_content,
|
58 |
-
)
|
59 |
-
);
|
60 |
-
|
61 |
-
$translate->setTranslateInline(true);
|
62 |
}
|
63 |
}
|
64 |
|
|
|
|
|
|
|
|
|
|
|
65 |
protected function _generateJobs($jobs, $exists)
|
66 |
{
|
67 |
$devMode = Mage::getStoreConfig(self::XML_PATH_DEVELOPER_MODE);
|
68 |
$devModeJobs = Mage::getStoreConfig(self::XML_PATH_DEVELOPER_MODE_JOBS);
|
69 |
-
$devModeJobs = preg_replace('/[^
|
70 |
$devModeJobs = explode(',', $devModeJobs);
|
71 |
|
72 |
if ($devMode) {
|
@@ -79,10 +158,104 @@ class Zero1_Crondoctor_Model_Observer extends Mage_Cron_Model_Observer
|
|
79 |
}
|
80 |
}
|
81 |
}
|
82 |
-
|
83 |
return parent::_generateJobs($devJobs, $exists);
|
84 |
}
|
85 |
-
|
86 |
return parent::_generateJobs($jobs, $exists);
|
87 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
88 |
}
|
1 |
<?php
|
2 |
class Zero1_Crondoctor_Model_Observer extends Mage_Cron_Model_Observer
|
3 |
{
|
|
|
|
|
|
|
|
|
4 |
const XML_PATH_DEVELOPER_MODE = 'zero1_crondoctor/settings/developer_mode';
|
5 |
const XML_PATH_DEVELOPER_MODE_JOBS = 'zero1_crondoctor/settings/developer_mode_jobs';
|
6 |
+
const STOP_FLAG_NAME = 'cron_stop.flag';
|
7 |
|
8 |
+
private $emulateRunTimes = array(
|
9 |
+
'core/observer::cleanCache' => 20,
|
10 |
+
'directory/observer::scheduledUpdateCurrencyRates' => 20,
|
11 |
+
'catalog/observer::reindexProductPrices' => 20,
|
12 |
+
'catalogrule/observer::dailyCatalogUpdate' => 20,
|
13 |
+
'sales/observer::cleanExpiredQuotes' => 20,
|
14 |
+
'sales/observer::aggregateSalesReportOrderData' => 20,
|
15 |
+
'sales/observer::aggregateSalesReportShipmentData' => 20,
|
16 |
+
'sales/observer::aggregateSalesReportInvoicedData' => 20,
|
17 |
+
'sales/observer::aggregateSalesReportRefundedData' => 20,
|
18 |
+
'sales/observer::aggregateSalesReportBestsellersData' => 20,
|
19 |
+
'salesrule/observer::aggregateSalesReportCouponsData' => 20,
|
20 |
+
'backup/observer::scheduledBackup' => 20,
|
21 |
+
'paypal/observer::fetchReports' => 20,
|
22 |
+
'log/cron::logClean' => 20,
|
23 |
+
'tax/observer::aggregateSalesReportTaxData' => 20,
|
24 |
+
'productalert/observer::process' => 20,
|
25 |
+
'captcha/observer::deleteOldAttempts' => 20,
|
26 |
+
'captcha/observer::deleteExpiredImages' => 20,
|
27 |
+
'newsletter/observer::scheduledSend' => 20,
|
28 |
+
'persistent/observer::clearExpiredCronJob' => 20,
|
29 |
+
'xmlconnect/observer::scheduledSend' => 20,
|
30 |
+
'awcore/logger::exorcise' => 20,
|
31 |
+
'followupemail/cron::cronJobs' => 20,
|
32 |
+
'followupemail/crondaily::cronJobs' => 20,
|
33 |
+
'amazonpayments/observer::rotateLogfiles' => 20,
|
34 |
+
'amazonpayments/observer::pollObjectsData' => 20,
|
35 |
+
'enterprise_index/observer::refreshIndex' => 20,
|
36 |
+
'enterprise_index/cron::scheduledCleanup' => 20,
|
37 |
+
'enterprise_giftcardaccount/cron::updateStates' => 20,
|
38 |
+
'enterprise_giftcardaccount/pool::applyCodesGeneration' => 20,
|
39 |
+
'enterprise_logging/observer::rotateLogs' => 20,
|
40 |
+
'seoredirects/observer::updateRedirectionsCronJob' => 20,
|
41 |
+
'enterprise_reminder/observer::scheduledNotification' => 20,
|
42 |
+
'enterprise_reward/observer::scheduledBalanceExpireNotification' => 20,
|
43 |
+
'enterprise_reward/observer::scheduledPointsExpiration' => 20,
|
44 |
+
'enterprise_salesarchive/observer::archiveOrdersByCron' => 20,
|
45 |
+
'enterprise_search/indexer_indexer::reindexAll' => 20,
|
46 |
+
'enterprise_targetrule/index::cron' => 20,
|
47 |
+
'enterprise_catalog/index_observer_price::refreshSpecialPrices' => 20,
|
48 |
+
'enterprise_staging/observer::automates' => 20,
|
49 |
+
'M2ePro/Cron_Type_Magento::process' => 1200,
|
50 |
+
'xsitemap/observer::scheduledGenerateSitemaps' => 20,
|
51 |
+
'ops/observer::cleanUpOldPaymentData' => 20,
|
52 |
+
'TrueShopping_UltraNotificationImport/observer::import' => 20,
|
53 |
+
'wsalogger/log::truncate' => 20,
|
54 |
+
'bibit/observer::checkNotify' => 180,
|
55 |
+
'channeladvisor/observer::pullOrders' => 20,
|
56 |
+
'channeladvisor/observer::syncStock' => 120,
|
57 |
+
'channeladvisor/observer::syncProducts' => 20,
|
58 |
+
'channeladvisorcse/observer::scheduledGenerateChanneladvisorCSE' => 20,
|
59 |
+
'zero1_crondoctor/observer::checkForZombieJobs' => 1,
|
60 |
+
'zero1_feeds/observer_temp::mail' => 20,
|
61 |
+
'solvitt/observer::receive' => 90,
|
62 |
+
'rmareport/observer::aggregateRmareportReportRmasData' => 20,
|
63 |
+
'enterprise_pagecache/crawler::crawl' => 20,
|
64 |
+
'enterprise_importexport/observer::scheduledLogClean' => 20,
|
65 |
+
'sitemap/observer::scheduledGenerateSitemaps' => 20,
|
66 |
+
'orderspro/observer::scheduledArchiveOrders' => 20,
|
67 |
+
'enterprise_importexport/observer::processScheduledOperation' => 20,
|
68 |
+
);
|
69 |
|
70 |
+
/**
|
71 |
+
* Process cron queue
|
72 |
+
* Generate tasks schedule
|
73 |
+
* Cleanup tasks schedule
|
74 |
+
*
|
75 |
+
* @param Varien_Event_Observer $observer
|
76 |
+
*/
|
77 |
+
public function dispatch($observer)
|
78 |
{
|
79 |
+
/* @var $schedules Mage_Cron_Model_Resource_Schedule_Collection */
|
80 |
+
$jobsRoot = Mage::getConfig()->getNode('crontab/jobs');
|
81 |
+
$defaultJobsRoot = Mage::getConfig()->getNode('default/crontab/jobs');
|
82 |
|
83 |
+
$nextJob = $this->getNextJob();
|
|
|
|
|
84 |
|
85 |
+
$maxIterationCounter = 0;
|
86 |
+
while($nextJob->count() == 1 && !$this->shouldStop() && $maxIterationCounter < 1000){
|
87 |
+
$maxIterationCounter++;
|
88 |
+
/** @var $schedule Mage_Cron_Model_Schedule */
|
89 |
+
$schedule = $nextJob->getFirstItem();
|
90 |
|
91 |
+
$jobConfig = $jobsRoot->{$schedule->getJobCode()};
|
92 |
+
if (!$jobConfig || !$jobConfig->run) {
|
93 |
+
$jobConfig = $defaultJobsRoot->{$schedule->getJobCode()};
|
94 |
+
if (!$jobConfig || !$jobConfig->run) {
|
95 |
+
continue;
|
96 |
+
}
|
97 |
}
|
98 |
+
$this->_processJob($schedule, $jobConfig);
|
99 |
+
|
100 |
+
$this->cleanUpJob($schedule);
|
101 |
+
$nextJob = $this->getNextJob();
|
102 |
+
}
|
103 |
+
}
|
104 |
|
105 |
+
/* @return Mage_Cron_Model_Resource_Schedule_Collection */
|
106 |
+
private function getNextJob(){
|
107 |
+
/* @var $collection Mage_Cron_Model_Resource_Schedule_Collection */
|
108 |
+
$collection = Mage::getModel('cron/schedule')->getCollection()
|
109 |
+
->addFieldToFilter('status', Mage_Cron_Model_Schedule::STATUS_PENDING)
|
110 |
+
->addFieldToFilter('scheduled_at', array('lteq' => strftime('%Y-%m-%d %H:%M:00', time())))
|
111 |
+
->addOrder('scheduled_at', 'ASC');
|
112 |
+
$collection->getSelect()->limit(1);
|
113 |
+
$collection->load();
|
114 |
+
return $collection;
|
115 |
+
}
|
116 |
|
117 |
+
private function cleanUpJob(Mage_Cron_Model_Schedule $schedule){
|
118 |
+
/* @var $collection Mage_Cron_Model_Resource_Schedule_Collection */
|
119 |
+
$collection = Mage::getModel('cron/schedule')->getCollection()
|
120 |
+
->addFieldToFilter('status', Mage_Cron_Model_Schedule::STATUS_PENDING)
|
121 |
+
->addFieldToFilter('job_code', $schedule->getJobCode())
|
122 |
+
->addFieldToFilter('scheduled_at', array('lt' => strftime('%Y-%m-%d %H:%M:00', time())));
|
123 |
|
124 |
+
/* @var $oldSchedule Mage_Cron_Model_Schedule */
|
125 |
+
foreach($collection as $oldSchedule){
|
126 |
+
$oldSchedule->setStatus(Mage_Cron_Model_Schedule::STATUS_MISSED)->save();
|
127 |
}
|
128 |
+
}
|
129 |
|
130 |
+
public static function shouldStop(){
|
131 |
+
if(file_exists(self::STOP_FLAG_NAME)){
|
132 |
+
//Mage::log('stop flag found', Zend_Log::DEBUG, 'cron.log', true);
|
133 |
+
return true;
|
134 |
+
}else{
|
135 |
+
return false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
136 |
}
|
137 |
}
|
138 |
|
139 |
+
public function schedule(Varien_Event_Observer $observer){
|
140 |
+
$this->generate();
|
141 |
+
$this->cleanup();
|
142 |
+
}
|
143 |
+
|
144 |
protected function _generateJobs($jobs, $exists)
|
145 |
{
|
146 |
$devMode = Mage::getStoreConfig(self::XML_PATH_DEVELOPER_MODE);
|
147 |
$devModeJobs = Mage::getStoreConfig(self::XML_PATH_DEVELOPER_MODE_JOBS);
|
148 |
+
$devModeJobs = preg_replace('/[^A-Za-z0-9_,]*/', '', $devModeJobs);
|
149 |
$devModeJobs = explode(',', $devModeJobs);
|
150 |
|
151 |
if ($devMode) {
|
158 |
}
|
159 |
}
|
160 |
}
|
|
|
161 |
return parent::_generateJobs($devJobs, $exists);
|
162 |
}
|
|
|
163 |
return parent::_generateJobs($jobs, $exists);
|
164 |
}
|
165 |
+
|
166 |
+
/**
|
167 |
+
* Process cron task
|
168 |
+
*
|
169 |
+
* @param Mage_Cron_Model_Schedule $schedule
|
170 |
+
* @param $jobConfig
|
171 |
+
* @param bool $isAlways
|
172 |
+
* @return Mage_Cron_Model_Observer
|
173 |
+
*/
|
174 |
+
protected function _processJob($schedule, $jobConfig, $isAlways = false)
|
175 |
+
{
|
176 |
+
$runConfig = $jobConfig->run;
|
177 |
+
if (!$isAlways) {
|
178 |
+
$scheduleLifetime = Mage::getStoreConfig(self::XML_PATH_SCHEDULE_LIFETIME) * 60;
|
179 |
+
$now = time();
|
180 |
+
$time = strtotime($schedule->getScheduledAt());
|
181 |
+
if ($time > $now) {
|
182 |
+
return;
|
183 |
+
}
|
184 |
+
}
|
185 |
+
|
186 |
+
$errorStatus = Mage_Cron_Model_Schedule::STATUS_ERROR;
|
187 |
+
try {
|
188 |
+
if (!$isAlways) {
|
189 |
+
if (($scheduleLifetime != 0) && ($time < $now - $scheduleLifetime)) {
|
190 |
+
$errorStatus = Mage_Cron_Model_Schedule::STATUS_MISSED;
|
191 |
+
Mage::throwException(Mage::helper('cron')->__('Too late for the schedule.'));
|
192 |
+
}
|
193 |
+
}
|
194 |
+
if ($runConfig->model) {
|
195 |
+
if (!preg_match(self::REGEX_RUN_MODEL, (string)$runConfig->model, $run)) {
|
196 |
+
Mage::throwException(Mage::helper('cron')->__('Invalid model/method definition, expecting "model/class::method".'));
|
197 |
+
}
|
198 |
+
if (!($model = Mage::getModel($run[1])) || !method_exists($model, $run[2])) {
|
199 |
+
Mage::throwException(Mage::helper('cron')->__('Invalid callback: %s::%s does not exist', $run[1], $run[2]));
|
200 |
+
}
|
201 |
+
$callback = array($model, $run[2]);
|
202 |
+
$arguments = array($schedule);
|
203 |
+
}
|
204 |
+
if (empty($callback)) {
|
205 |
+
Mage::throwException(Mage::helper('cron')->__('No callbacks found'));
|
206 |
+
}
|
207 |
+
|
208 |
+
if (!$isAlways) {
|
209 |
+
if (!$schedule->tryLockJob()) {
|
210 |
+
// another cron started this job intermittently, so skip it
|
211 |
+
return;
|
212 |
+
}
|
213 |
+
/**
|
214 |
+
though running status is set in tryLockJob we must set it here because the object
|
215 |
+
was loaded with a pending status and will set it back to pending if we don't set it here
|
216 |
+
*/
|
217 |
+
}
|
218 |
+
|
219 |
+
$schedule
|
220 |
+
->setExecutedAt(strftime('%Y-%m-%d %H:%M:%S', time()))
|
221 |
+
->setStatus(Mage_Cron_Model_Schedule::STATUS_RUNNING)
|
222 |
+
->save();
|
223 |
+
|
224 |
+
call_user_func_array($callback, $arguments);
|
225 |
+
|
226 |
+
/* Emulation Code
|
227 |
+
*
|
228 |
+
$runModel = (string)$jobConfig->run->model;
|
229 |
+
if(isset($this->emulateRunTimes[$runModel])){
|
230 |
+
Mage::log($schedule->getJobCode().' '.$runModel.'::'.$this->emulateRunTimes[$runModel], Zend_Log::DEBUG, 'cron.log', true);
|
231 |
+
|
232 |
+
$lateness = time() - strtotime($schedule->getScheduledAt());
|
233 |
+
$latenessFactor = 0.01; //for every 100 seconds late it increase the run time by 1
|
234 |
+
$runtime = ($lateness * $latenessFactor) + $this->emulateRunTimes[$runModel];
|
235 |
+
|
236 |
+
if($schedule->getJobCode() == 'enterprise_refresh_index'){
|
237 |
+
$runtime = 45;
|
238 |
+
}
|
239 |
+
|
240 |
+
Mage::log('runtime: '.$runtime, Zend_Log::DEBUG, 'cron.log', true);
|
241 |
+
sleep($runtime);
|
242 |
+
}else{
|
243 |
+
Mage::log($runModel.'::no sleep time', Zend_Log::DEBUG, 'cron.log', true);
|
244 |
+
}
|
245 |
+
*/
|
246 |
+
|
247 |
+
//need to reload so we don't overwrite anything that has changed since running
|
248 |
+
$schedule->load($schedule->getId());
|
249 |
+
$schedule
|
250 |
+
->setStatus(Mage_Cron_Model_Schedule::STATUS_SUCCESS)
|
251 |
+
->setFinishedAt(strftime('%Y-%m-%d %H:%M:%S', time()));
|
252 |
+
|
253 |
+
} catch (Exception $e) {
|
254 |
+
$schedule->setStatus($errorStatus)
|
255 |
+
->setMessages($e->__toString());
|
256 |
+
}
|
257 |
+
$schedule->save();
|
258 |
+
|
259 |
+
return $this;
|
260 |
+
}
|
261 |
}
|
app/code/community/Zero1/Crondoctor/Model/Observer/Zombie.php
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
class Zero1_Crondoctor_Model_Observer_Zombie{
|
3 |
+
|
4 |
+
const XML_PATH_ZOMBIE_EMAIL_TEMPLATE = 'zero1_crondoctor/settings/zombie_email_template';
|
5 |
+
const XML_PATH_ZOMBIE_EMAIL_TO = 'zero1_crondoctor/settings/zombie_email';
|
6 |
+
const XML_PATH_ZOMBIE_TIME = 'zero1_crondoctor/settings/zombie_time';
|
7 |
+
|
8 |
+
const XML_PATH_DEVELOPER_MODE = 'zero1_crondoctor/settings/developer_mode';
|
9 |
+
const XML_PATH_DEVELOPER_MODE_JOBS = 'zero1_crondoctor/settings/developer_mode_jobs';
|
10 |
+
|
11 |
+
protected $_zombieEmailSubject = 'Magento Cron Doctor Zombie Report';
|
12 |
+
|
13 |
+
public function checkForZombieJobs(Varien_Event_Observer $event){
|
14 |
+
$storeId = Mage::app()->getStore()->getId();
|
15 |
+
$to = Mage::getStoreConfig(self::XML_PATH_ZOMBIE_EMAIL_TO, $storeId);
|
16 |
+
|
17 |
+
if(!$to) {
|
18 |
+
return; // No destination address.
|
19 |
+
}
|
20 |
+
|
21 |
+
$cronjob_collection = Mage::getModel('cron/schedule')->getCollection();
|
22 |
+
$cronjob_collection->addFieldToFilter('job_code', array('nin' => array(
|
23 |
+
'enterprise_refresh_index', //Ignore always jobs, TODO <<properly
|
24 |
+
)));
|
25 |
+
$cronjob_collection->addFieldToFilter('status', array(
|
26 |
+
'eq' => Mage_Cron_Model_Schedule::STATUS_RUNNING)
|
27 |
+
);
|
28 |
+
|
29 |
+
$job_list_content = '';
|
30 |
+
foreach($cronjob_collection as $cronjob) {
|
31 |
+
if($cronjob->getReportedAt()) {
|
32 |
+
continue; // No need to report more then once.
|
33 |
+
}
|
34 |
+
|
35 |
+
$running_time = ceil((time() - strtotime($cronjob->getExecutedAt())) / 60);
|
36 |
+
|
37 |
+
if($running_time >= Mage::getStoreConfig(self::XML_PATH_ZOMBIE_TIME, $storeId)) {
|
38 |
+
$job_list_content .= '"'.ucwords(str_replace('_', ' ', $cronjob->getJobCode()))."'";
|
39 |
+
$job_list_content .= ' has been running for '.$running_time.' minutes.<br/>';
|
40 |
+
|
41 |
+
$cronjob->setReportedAt(strftime('%Y-%m-%d %H:%M:%S', time()));
|
42 |
+
$cronjob->save();
|
43 |
+
}
|
44 |
+
}
|
45 |
+
|
46 |
+
if($job_list_content != '') {
|
47 |
+
$translate = Mage::getSingleton('core/translate');
|
48 |
+
$translate->setTranslateInline(false);
|
49 |
+
|
50 |
+
Mage::getModel('core/email_template')
|
51 |
+
->setDesignConfig(array('area' => 'frontend', 'store' => $storeId))
|
52 |
+
->sendTransactional(
|
53 |
+
Mage::getStoreConfig(self::XML_PATH_ZOMBIE_EMAIL_TEMPLATE, $storeId),
|
54 |
+
Mage::getStoreConfig(Mage_Sales_Model_Order::XML_PATH_EMAIL_IDENTITY, $storeId),
|
55 |
+
$to,
|
56 |
+
null,
|
57 |
+
array(
|
58 |
+
'subject' => $this->_zombieEmailSubject,
|
59 |
+
'job_list_content' => $job_list_content,
|
60 |
+
)
|
61 |
+
);
|
62 |
+
|
63 |
+
$translate->setTranslateInline(true);
|
64 |
+
}
|
65 |
+
}
|
66 |
+
}
|
app/code/community/Zero1/Crondoctor/Model/Schedule.php
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
class Zero1_Crondoctor_Model_Schedule extends Mage_Cron_Model_Schedule{
|
3 |
+
|
4 |
+
protected function _beforeSave(){
|
5 |
+
parent::_beforeSave();
|
6 |
+
$this->setUpdatedAt(strftime('%Y-%m-%d %H:%M:%S', time()));
|
7 |
+
}
|
8 |
+
|
9 |
+
}
|
app/code/community/Zero1/Crondoctor/Model/Schedule/Job.php
ADDED
@@ -0,0 +1,182 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Class Zero1_Crondoctor_Model_Schedule_Job
|
5 |
+
*
|
6 |
+
* @method string getJobCode()
|
7 |
+
* @method Zero1_CronDebug_Model_Schedule_Job setJobConfig(Mage_Core_Model_Config_Element $config)
|
8 |
+
* @method Mage_Core_Model_Config_Element getJobConfig()
|
9 |
+
* @method Zero1_CronDebug_Model_Schedule_Job setScheduleFrom(int $timestamp)
|
10 |
+
* @method int getScheduleFrom()
|
11 |
+
* @method Zero1_CronDebug_Model_Schedule_Job setScheduleUntil(int $timestamp)
|
12 |
+
* @method int getScheduleUntil()
|
13 |
+
* @method Zero1_CronDebug_Model_Schedule_Job setJobType(string $type)
|
14 |
+
* @method string getJobType()
|
15 |
+
*/
|
16 |
+
class Zero1_Crondoctor_Model_Schedule_Job extends Mage_Cron_Model_Schedule{
|
17 |
+
|
18 |
+
private $messages = array();
|
19 |
+
private $processes = array();
|
20 |
+
private $stats = null;
|
21 |
+
|
22 |
+
const TYPE_DEFAULT = 'default';
|
23 |
+
const TYPE_ALWAYS = 'always';
|
24 |
+
|
25 |
+
public function __construct(){
|
26 |
+
|
27 |
+
$args = func_get_args();
|
28 |
+
if (empty($args[0])) {
|
29 |
+
$args[0] = array();
|
30 |
+
}
|
31 |
+
|
32 |
+
if(!isset($args[0]['job_code'], $args[0]['job_config'], $args[0]['from'], $args[0]['until'])){
|
33 |
+
throw new InvalidArgumentException(
|
34 |
+
'Missing an argument, expecting job_code, job_config, from, until. Got: '.json_encode(array_keys($args[0]))
|
35 |
+
);
|
36 |
+
}
|
37 |
+
|
38 |
+
$this->setJobCode($args[0]['job_code']);
|
39 |
+
$this->setJobConfig($args[0]['job_config']);
|
40 |
+
$this->setScheduleFrom($args[0]['from']);
|
41 |
+
$this->setScheduleUntil($args[0]['until']);
|
42 |
+
$this->setJobType(($this->getCronExpr() == 'always')? self::TYPE_ALWAYS : self::TYPE_DEFAULT);
|
43 |
+
|
44 |
+
$this->generateSchedule($this->getScheduleFrom(), $this->getScheduleUntil());
|
45 |
+
}
|
46 |
+
|
47 |
+
/** @return String */
|
48 |
+
public function getCronExpr(){
|
49 |
+
|
50 |
+
$cronExpr = $this->getData('cron_expr');
|
51 |
+
if($cronExpr === null){
|
52 |
+
|
53 |
+
$cronExpr = '';
|
54 |
+
|
55 |
+
if($this->getJobConfig()->schedule->config_path){
|
56 |
+
$cronExpr = Mage::getStoreConfig((string)$this->getJobConfig()->schedule->config_path);
|
57 |
+
}
|
58 |
+
|
59 |
+
if(empty($cronExpr) && $this->getJobConfig()->schedule->cron_expr){
|
60 |
+
$cronExpr = (string)$this->getJobConfig()->schedule->cron_expr;
|
61 |
+
}
|
62 |
+
|
63 |
+
$this->setData('cron_expr', $cronExpr);
|
64 |
+
}
|
65 |
+
|
66 |
+
return $this->getData('cron_expr');
|
67 |
+
}
|
68 |
+
|
69 |
+
public function getCronExprArr(){
|
70 |
+
|
71 |
+
if($this->getData('cron_expr_arr') === null){
|
72 |
+
$cronExpr = $this->getCronExpr();
|
73 |
+
if($cronExpr == '' || $this->getJobType() == self::TYPE_ALWAYS){
|
74 |
+
$this->setData('cron_expr_arr', array());
|
75 |
+
}else{
|
76 |
+
$e = preg_split('#\s+#', $cronExpr, null, PREG_SPLIT_NO_EMPTY);
|
77 |
+
if (sizeof($e)<5 || sizeof($e)>6) {
|
78 |
+
$this->addScheduleMessage('Cron Expr is invalid: '.$cronExpr);
|
79 |
+
$this->setData('cron_expr_arr', array());
|
80 |
+
}else{
|
81 |
+
$this->setData('cron_expr_arr', $e);
|
82 |
+
}
|
83 |
+
}
|
84 |
+
}
|
85 |
+
return $this->getData('cron_expr_arr');
|
86 |
+
}
|
87 |
+
|
88 |
+
private function generateSchedule($from, $until){
|
89 |
+
|
90 |
+
$cronExprArr = $this->getCronExprArr();
|
91 |
+
|
92 |
+
if(empty($cronExprArr)){
|
93 |
+
return;
|
94 |
+
}
|
95 |
+
|
96 |
+
$from -= ($from % 60); //make sure its on an exact min
|
97 |
+
|
98 |
+
|
99 |
+
while($from < $until){
|
100 |
+
|
101 |
+
$d = getdate(Mage::getSingleton('core/date')->timestamp($from));
|
102 |
+
|
103 |
+
$match = $this->matchCronExpression($cronExprArr[0], $d['minutes'])
|
104 |
+
&& $this->matchCronExpression($cronExprArr[1], $d['hours'])
|
105 |
+
&& $this->matchCronExpression($cronExprArr[2], $d['mday'])
|
106 |
+
&& $this->matchCronExpression($cronExprArr[3], $d['mon'])
|
107 |
+
&& $this->matchCronExpression($cronExprArr[4], $d['wday']);
|
108 |
+
|
109 |
+
if($match){
|
110 |
+
|
111 |
+
$this->addProcess(
|
112 |
+
Mage::getModel('zero1_crondoctor/schedule_job_process', array(
|
113 |
+
'scheduled_at' => $from,
|
114 |
+
'job' => $this,
|
115 |
+
))
|
116 |
+
);
|
117 |
+
}
|
118 |
+
|
119 |
+
$from += 60;
|
120 |
+
}
|
121 |
+
}
|
122 |
+
|
123 |
+
private function addProcess(Zero1_Crondoctor_Model_Schedule_Job_Process $process){
|
124 |
+
$this->processes[$process->getScheduledAt()] = $process;
|
125 |
+
}
|
126 |
+
public function getProcesses(){
|
127 |
+
return $this->processes;
|
128 |
+
}
|
129 |
+
|
130 |
+
|
131 |
+
private function addScheduleMessage($msg){
|
132 |
+
$this->messages[] = $msg;
|
133 |
+
}
|
134 |
+
private function getScheduleMessages($lineBreak = '<br />'){
|
135 |
+
return implode($lineBreak, $this->messages);
|
136 |
+
}
|
137 |
+
|
138 |
+
public function getStatValue($key){
|
139 |
+
$stats = $this->getStats();
|
140 |
+
if(isset($stats[$key], $stats[$key]['value'])){
|
141 |
+
return $stats[$key]['value'];
|
142 |
+
}else{
|
143 |
+
return 0;
|
144 |
+
}
|
145 |
+
}
|
146 |
+
|
147 |
+
public function getStats(){
|
148 |
+
if(!$this->stats){
|
149 |
+
$this->stats = array(
|
150 |
+
'scheduled_misses' => $this->getScheduledMisses(),
|
151 |
+
'expected_runs' => $this->calculateExpectedRuns(),
|
152 |
+
);
|
153 |
+
|
154 |
+
}
|
155 |
+
return $this->stats;
|
156 |
+
}
|
157 |
+
|
158 |
+
private function getScheduledMisses(){
|
159 |
+
$misses = 0;
|
160 |
+
/* @var $process Zero1_Crondoctor_Model_Schedule_Job_Process */
|
161 |
+
foreach($this->processes as $timestamp => $process){
|
162 |
+
if($process->getStatus() == Mage_Cron_Model_Schedule::STATUS_MISSED){
|
163 |
+
$misses++;
|
164 |
+
}
|
165 |
+
}
|
166 |
+
return array(
|
167 |
+
'name' => 'Scheduled Misses',
|
168 |
+
'value' => $misses,
|
169 |
+
'description' => 'Number of times the job has been schedule, but then missed (due to being run too late)',
|
170 |
+
);
|
171 |
+
}
|
172 |
+
|
173 |
+
private function calculateExpectedRuns(){
|
174 |
+
return array(
|
175 |
+
'name' => 'Expected Runs',
|
176 |
+
'value' => count($this->getProcesses()),
|
177 |
+
'description' => 'Number of times the job should run in a perfect world',
|
178 |
+
);
|
179 |
+
}
|
180 |
+
|
181 |
+
|
182 |
+
}
|
app/code/community/Zero1/Crondoctor/Model/Schedule/Job/Process.php
ADDED
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Class Zero1_Crondoctor_Model_Schedule_Job_Process
|
5 |
+
*
|
6 |
+
* @method int getScheduledAt()
|
7 |
+
* @method Zero1_CronDebug_Model_Schedule_Job getJob()
|
8 |
+
* @method Zero1_CronDebug_Model_Schedule_Job setScheduleId(int $scheduleId)
|
9 |
+
* @method int getScheduledId()
|
10 |
+
* @method Zero1_CronDebug_Model_Schedule_Job setStatus(string $status)
|
11 |
+
* @method string getStatus()
|
12 |
+
* @method Zero1_CronDebug_Model_Schedule_Job setMessage(string $msg)
|
13 |
+
* @method string getMessage()
|
14 |
+
* @method Zero1_CronDebug_Model_Schedule_Job setCreatedAt(int $timestamp)
|
15 |
+
* @method int|null getCreatedAt()
|
16 |
+
* @method Zero1_CronDebug_Model_Schedule_Job setExecutedAt(int $timestamp)
|
17 |
+
* @method int|null getExecutedAt()
|
18 |
+
* @method Zero1_CronDebug_Model_Schedule_Job setFinishedAt(int $timestamp)
|
19 |
+
* @method int|null getFinishedAt()
|
20 |
+
*
|
21 |
+
*/
|
22 |
+
class Zero1_Crondoctor_Model_Schedule_Job_Process extends Varien_Object{
|
23 |
+
|
24 |
+
public function _construct(){
|
25 |
+
parent::_construct();
|
26 |
+
|
27 |
+
$this->importCronSchedule();
|
28 |
+
}
|
29 |
+
|
30 |
+
private function importCronSchedule(){
|
31 |
+
/* @var $cronScheduleCollection Mage_Cron_Model_Resource_Schedule_Collection */
|
32 |
+
$cronScheduleCollection = Mage::getModel('cron/schedule')->getCollection();
|
33 |
+
|
34 |
+
$cronScheduleCollection->addFieldToFilter('job_code', $this->getJob()->getJobCode());
|
35 |
+
$cronScheduleCollection->addFieldToFilter('scheduled_at', strftime('%Y-%m-%d %H:%M', $this->getScheduledAt()));
|
36 |
+
|
37 |
+
if($cronScheduleCollection->count()){
|
38 |
+
$this->import($cronScheduleCollection->getFirstItem());
|
39 |
+
}
|
40 |
+
}
|
41 |
+
|
42 |
+
private function import(Mage_Cron_Model_Schedule $cron){
|
43 |
+
|
44 |
+
$this->setScheduleId($cron->getScheduleId());
|
45 |
+
$this->setScheduledAt(strtotime($cron->getScheduledAt()));
|
46 |
+
$this->setStatus($cron->getStatus());
|
47 |
+
$this->setMessage((($cron->getMessages() != null)? $cron->getMessages() : ''));
|
48 |
+
$this->setCreatedAt(strtotime($cron->getCreatedAt()));
|
49 |
+
$this->setExecutedAt((($cron->getExecutedAt() == null)? null : strtotime($cron->getExecutedAt())));
|
50 |
+
$this->setFinishedAt((($cron->getFinishedAt() == null)? null : strtotime($cron->getFinishedAt())));
|
51 |
+
}
|
52 |
+
}
|
app/code/community/Zero1/Crondoctor/Model/Visual/Schedule.php
ADDED
@@ -0,0 +1,102 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
class Zero1_Crondoctor_Model_Visual_Schedule{
|
3 |
+
|
4 |
+
private $schedule = array();
|
5 |
+
private $jobNodes = array(
|
6 |
+
'crontab/jobs',
|
7 |
+
'default/crontab/jobs',
|
8 |
+
);
|
9 |
+
private $orderingBy = null;
|
10 |
+
|
11 |
+
public function __construct($args){
|
12 |
+
if(isset($args['until'])){
|
13 |
+
$this->generateScheduleForDateRange(
|
14 |
+
$args['until'],
|
15 |
+
(isset($args['from'])? $args['from'] : null)
|
16 |
+
);
|
17 |
+
}
|
18 |
+
}
|
19 |
+
|
20 |
+
public function generateScheduleForDateRange($until, $from = null){
|
21 |
+
$this->cleanUpOldScheduling();
|
22 |
+
$from = $this->getFromTime($from);
|
23 |
+
|
24 |
+
$c = 0;
|
25 |
+
|
26 |
+
foreach($this->jobNodes as $jobNode){
|
27 |
+
$jobNodeConfig = Mage::getConfig()->getNode($jobNode);
|
28 |
+
if($jobNodeConfig instanceof Mage_Core_Model_Config_Element){
|
29 |
+
foreach($jobNodeConfig->children() as $jobCode => $jobConfig){
|
30 |
+
|
31 |
+
$validCodes = array(
|
32 |
+
//'zero1_cron_debug_5min',
|
33 |
+
//'zero1_cron_debug_2min',
|
34 |
+
//'enterprise_staging_automates',
|
35 |
+
);
|
36 |
+
if(array_search($jobCode, $validCodes) === false){
|
37 |
+
//continue;
|
38 |
+
}
|
39 |
+
$this->addToSchedule($this->getScheduleJob(
|
40 |
+
$jobCode, $jobConfig, $from, $until
|
41 |
+
));
|
42 |
+
if($c++ == 5){
|
43 |
+
//break;
|
44 |
+
}
|
45 |
+
}
|
46 |
+
}
|
47 |
+
}
|
48 |
+
}
|
49 |
+
|
50 |
+
private function getFromTime($from){
|
51 |
+
if($from === null){
|
52 |
+
return time();
|
53 |
+
}else{
|
54 |
+
return $from;
|
55 |
+
}
|
56 |
+
}
|
57 |
+
|
58 |
+
private function cleanUpOldScheduling(){
|
59 |
+
$this->schedule = array();
|
60 |
+
}
|
61 |
+
|
62 |
+
private function addToSchedule(Zero1_Crondoctor_Model_Visual_Schedule_Job $job){
|
63 |
+
$this->schedule[$job->getJobCode()] = $job;
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* @param $jobCode
|
68 |
+
* @param $jobConfig
|
69 |
+
* @param $from
|
70 |
+
* @param $until
|
71 |
+
* @return Zero1_Crondoctor_Model_Visual_Schedule_Job
|
72 |
+
*/
|
73 |
+
public function getScheduleJob($jobCode, $jobConfig, $from, $until){
|
74 |
+
|
75 |
+
$scheduleJob = Mage::getModel('zero1_crondoctor/visual_schedule_job', array(
|
76 |
+
'job_code' => $jobCode,
|
77 |
+
'job_config' => $jobConfig,
|
78 |
+
'from' => $from,
|
79 |
+
'until' => $until,
|
80 |
+
));
|
81 |
+
|
82 |
+
return $scheduleJob;
|
83 |
+
}
|
84 |
+
|
85 |
+
public function getSchedule(){
|
86 |
+
return $this->schedule;
|
87 |
+
}
|
88 |
+
|
89 |
+
public function orderBy($orderBy){
|
90 |
+
$this->orderingBy = $orderBy;
|
91 |
+
uasort($this->schedule, array($this, 'uasort'));
|
92 |
+
}
|
93 |
+
|
94 |
+
private function uasort($a, $b){
|
95 |
+
/* @var $a Zero1_Crondoctor_Model_Visual_Schedule_Job */
|
96 |
+
/* @var $b Zero1_Crondoctor_Model_Visual_Schedule_Job */
|
97 |
+
if ($a->getStatValue($this->orderingBy) == $b->getStatValue($this->orderingBy)) {
|
98 |
+
return 0;
|
99 |
+
}
|
100 |
+
return ($a->getStatValue($this->orderingBy) < $b->getStatValue($this->orderingBy)) ? 1 : -1;
|
101 |
+
}
|
102 |
+
}
|
app/code/community/Zero1/Crondoctor/Model/Visual/Schedule/Job.php
ADDED
@@ -0,0 +1,182 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Class Zero1_Crondoctor_Model_Visual_Schedule_Job
|
5 |
+
*
|
6 |
+
* @method string getJobCode()
|
7 |
+
* @method Zero1_Crondoctor_Model_Visual_Schedule_Job setJobConfig(Mage_Core_Model_Config_Element $config)
|
8 |
+
* @method Mage_Core_Model_Config_Element getJobConfig()
|
9 |
+
* @method Zero1_Crondoctor_Model_Visual_Schedule_Job setScheduleFrom(int $timestamp)
|
10 |
+
* @method int getScheduleFrom()
|
11 |
+
* @method Zero1_Crondoctor_Model_Visual_Schedule_Job setScheduleUntil(int $timestamp)
|
12 |
+
* @method int getScheduleUntil()
|
13 |
+
* @method Zero1_Crondoctor_Model_Visual_Schedule_Job setJobType(string $type)
|
14 |
+
* @method string getJobType()
|
15 |
+
*/
|
16 |
+
class Zero1_Crondoctor_Model_Visual_Schedule_Job extends Mage_Cron_Model_Schedule{
|
17 |
+
|
18 |
+
private $messages = array();
|
19 |
+
private $processes = array();
|
20 |
+
private $stats = null;
|
21 |
+
|
22 |
+
const TYPE_DEFAULT = 'default';
|
23 |
+
const TYPE_ALWAYS = 'always';
|
24 |
+
|
25 |
+
public function __construct(){
|
26 |
+
|
27 |
+
$args = func_get_args();
|
28 |
+
if (empty($args[0])) {
|
29 |
+
$args[0] = array();
|
30 |
+
}
|
31 |
+
|
32 |
+
if(!isset($args[0]['job_code'], $args[0]['job_config'], $args[0]['from'], $args[0]['until'])){
|
33 |
+
throw new InvalidArgumentException(
|
34 |
+
'Missing an argument, expecting job_code, job_config, from, until. Got: '.json_encode(array_keys($args[0]))
|
35 |
+
);
|
36 |
+
}
|
37 |
+
|
38 |
+
$this->setJobCode($args[0]['job_code']);
|
39 |
+
$this->setJobConfig($args[0]['job_config']);
|
40 |
+
$this->setScheduleFrom($args[0]['from']);
|
41 |
+
$this->setScheduleUntil($args[0]['until']);
|
42 |
+
$this->setJobType(($this->getCronExpr() == 'always')? self::TYPE_ALWAYS : self::TYPE_DEFAULT);
|
43 |
+
|
44 |
+
$this->generateSchedule($this->getScheduleFrom(), $this->getScheduleUntil());
|
45 |
+
}
|
46 |
+
|
47 |
+
/** @return String */
|
48 |
+
public function getCronExpr(){
|
49 |
+
|
50 |
+
$cronExpr = $this->getData('cron_expr');
|
51 |
+
if($cronExpr === null){
|
52 |
+
|
53 |
+
$cronExpr = '';
|
54 |
+
|
55 |
+
if($this->getJobConfig()->schedule->config_path){
|
56 |
+
$cronExpr = Mage::getStoreConfig((string)$this->getJobConfig()->schedule->config_path);
|
57 |
+
}
|
58 |
+
|
59 |
+
if(empty($cronExpr) && $this->getJobConfig()->schedule->cron_expr){
|
60 |
+
$cronExpr = (string)$this->getJobConfig()->schedule->cron_expr;
|
61 |
+
}
|
62 |
+
|
63 |
+
$this->setData('cron_expr', $cronExpr);
|
64 |
+
}
|
65 |
+
|
66 |
+
return $this->getData('cron_expr');
|
67 |
+
}
|
68 |
+
|
69 |
+
public function getCronExprArr(){
|
70 |
+
|
71 |
+
if($this->getData('cron_expr_arr') === null){
|
72 |
+
$cronExpr = $this->getCronExpr();
|
73 |
+
if($cronExpr == '' || $this->getJobType() == self::TYPE_ALWAYS){
|
74 |
+
$this->setData('cron_expr_arr', array());
|
75 |
+
}else{
|
76 |
+
$e = preg_split('#\s+#', $cronExpr, null, PREG_SPLIT_NO_EMPTY);
|
77 |
+
if (sizeof($e)<5 || sizeof($e)>6) {
|
78 |
+
$this->addScheduleMessage('Cron Expr is invalid: '.$cronExpr);
|
79 |
+
$this->setData('cron_expr_arr', array());
|
80 |
+
}else{
|
81 |
+
$this->setData('cron_expr_arr', $e);
|
82 |
+
}
|
83 |
+
}
|
84 |
+
}
|
85 |
+
return $this->getData('cron_expr_arr');
|
86 |
+
}
|
87 |
+
|
88 |
+
private function generateSchedule($from, $until){
|
89 |
+
|
90 |
+
$cronExprArr = $this->getCronExprArr();
|
91 |
+
|
92 |
+
if(empty($cronExprArr)){
|
93 |
+
return;
|
94 |
+
}
|
95 |
+
|
96 |
+
$from -= ($from % 60); //make sure its on an exact min
|
97 |
+
|
98 |
+
|
99 |
+
while($from < $until){
|
100 |
+
|
101 |
+
$d = getdate(Mage::getSingleton('core/date')->timestamp($from));
|
102 |
+
|
103 |
+
$match = $this->matchCronExpression($cronExprArr[0], $d['minutes'])
|
104 |
+
&& $this->matchCronExpression($cronExprArr[1], $d['hours'])
|
105 |
+
&& $this->matchCronExpression($cronExprArr[2], $d['mday'])
|
106 |
+
&& $this->matchCronExpression($cronExprArr[3], $d['mon'])
|
107 |
+
&& $this->matchCronExpression($cronExprArr[4], $d['wday']);
|
108 |
+
|
109 |
+
if($match){
|
110 |
+
|
111 |
+
$this->addProcess(
|
112 |
+
Mage::getModel('zero1_crondoctor/visual_schedule_job_process', array(
|
113 |
+
'scheduled_at' => $from,
|
114 |
+
'job' => $this,
|
115 |
+
))
|
116 |
+
);
|
117 |
+
}
|
118 |
+
|
119 |
+
$from += 60;
|
120 |
+
}
|
121 |
+
}
|
122 |
+
|
123 |
+
private function addProcess(Zero1_Crondoctor_Model_Visual_Schedule_Job_Process $process){
|
124 |
+
$this->processes[$process->getScheduledAt()] = $process;
|
125 |
+
}
|
126 |
+
public function getProcesses(){
|
127 |
+
return $this->processes;
|
128 |
+
}
|
129 |
+
|
130 |
+
|
131 |
+
private function addScheduleMessage($msg){
|
132 |
+
$this->messages[] = $msg;
|
133 |
+
}
|
134 |
+
private function getScheduleMessages($lineBreak = '<br />'){
|
135 |
+
return implode($lineBreak, $this->messages);
|
136 |
+
}
|
137 |
+
|
138 |
+
public function getStatValue($key){
|
139 |
+
$stats = $this->getStats();
|
140 |
+
if(isset($stats[$key], $stats[$key]['value'])){
|
141 |
+
return $stats[$key]['value'];
|
142 |
+
}else{
|
143 |
+
return 0;
|
144 |
+
}
|
145 |
+
}
|
146 |
+
|
147 |
+
public function getStats(){
|
148 |
+
if(!$this->stats){
|
149 |
+
$this->stats = array(
|
150 |
+
'scheduled_misses' => $this->getScheduledMisses(),
|
151 |
+
'expected_runs' => $this->calculateExpectedRuns(),
|
152 |
+
);
|
153 |
+
|
154 |
+
}
|
155 |
+
return $this->stats;
|
156 |
+
}
|
157 |
+
|
158 |
+
private function getScheduledMisses(){
|
159 |
+
$misses = 0;
|
160 |
+
/* @var $process Zero1_Crondoctor_Model_Visual_Schedule_Job_Process */
|
161 |
+
foreach($this->processes as $timestamp => $process){
|
162 |
+
if($process->getStatus() == Mage_Cron_Model_Schedule::STATUS_MISSED){
|
163 |
+
$misses++;
|
164 |
+
}
|
165 |
+
}
|
166 |
+
return array(
|
167 |
+
'name' => 'Scheduled Misses',
|
168 |
+
'value' => $misses,
|
169 |
+
'description' => 'Number of times the job has been schedule, but then missed (due to being run too late)',
|
170 |
+
);
|
171 |
+
}
|
172 |
+
|
173 |
+
private function calculateExpectedRuns(){
|
174 |
+
return array(
|
175 |
+
'name' => 'Expected Runs',
|
176 |
+
'value' => count($this->getProcesses()),
|
177 |
+
'description' => 'Number of times the job should run in a perfect world',
|
178 |
+
);
|
179 |
+
}
|
180 |
+
|
181 |
+
|
182 |
+
}
|
app/code/community/Zero1/Crondoctor/Model/Visual/Schedule/Job/Process.php
ADDED
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Class Zero1_Crondoctor_Model_Visual_Schedule_Job_Process
|
5 |
+
*
|
6 |
+
* @method int getScheduledAt()
|
7 |
+
* @method Zero1_Crondoctor_Model_Visual_Schedule_Job getJob()
|
8 |
+
* @method Zero1_Crondoctor_Model_Visual_Schedule_Job setScheduleId(int $scheduleId)
|
9 |
+
* @method int getScheduledId()
|
10 |
+
* @method Zero1_Crondoctor_Model_Visual_Schedule_Job setStatus(string $status)
|
11 |
+
* @method string getStatus()
|
12 |
+
* @method Zero1_Crondoctor_Model_Visual_Schedule_Job setMessage(string $msg)
|
13 |
+
* @method string getMessage()
|
14 |
+
* @method Zero1_Crondoctor_Model_Visual_Schedule_Job setCreatedAt(int $timestamp)
|
15 |
+
* @method int|null getCreatedAt()
|
16 |
+
* @method Zero1_Crondoctor_Model_Visual_Schedule_Job setExecutedAt(int $timestamp)
|
17 |
+
* @method int|null getExecutedAt()
|
18 |
+
* @method Zero1_Crondoctor_Model_Visual_Schedule_Job setFinishedAt(int $timestamp)
|
19 |
+
* @method int|null getFinishedAt()
|
20 |
+
* @method Zero1_Crondoctor_Model_Visual_Schedule_Job setUpdatedAt(int $timestamp)
|
21 |
+
* @method int|null getUpdatedAt()
|
22 |
+
*/
|
23 |
+
class Zero1_Crondoctor_Model_Visual_Schedule_Job_Process extends Varien_Object{
|
24 |
+
|
25 |
+
public function _construct(){
|
26 |
+
parent::_construct();
|
27 |
+
|
28 |
+
$this->importCronSchedule();
|
29 |
+
}
|
30 |
+
|
31 |
+
private function importCronSchedule(){
|
32 |
+
/* @var $cronScheduleCollection Mage_Cron_Model_Resource_Schedule_Collection */
|
33 |
+
$cronScheduleCollection = Mage::getModel('cron/schedule')->getCollection();
|
34 |
+
|
35 |
+
$cronScheduleCollection->addFieldToFilter('job_code', $this->getJob()->getJobCode());
|
36 |
+
$cronScheduleCollection->addFieldToFilter('scheduled_at', strftime('%Y-%m-%d %H:%M', $this->getScheduledAt()));
|
37 |
+
|
38 |
+
if($cronScheduleCollection->count()){
|
39 |
+
$this->import($cronScheduleCollection->getFirstItem());
|
40 |
+
}
|
41 |
+
}
|
42 |
+
|
43 |
+
private function import(Mage_Cron_Model_Schedule $cron){
|
44 |
+
|
45 |
+
$this->setScheduleId($cron->getScheduleId());
|
46 |
+
$this->setScheduledAt(strtotime($cron->getScheduledAt()));
|
47 |
+
$this->setStatus($cron->getStatus());
|
48 |
+
$this->setMessage((($cron->getMessages() != null)? $cron->getMessages() : ''));
|
49 |
+
$this->setCreatedAt(strtotime($cron->getCreatedAt()));
|
50 |
+
$this->setExecutedAt((($cron->getExecutedAt() == null)? null : strtotime($cron->getExecutedAt())));
|
51 |
+
$this->setFinishedAt((($cron->getFinishedAt() == null)? null : strtotime($cron->getFinishedAt())));
|
52 |
+
$this->setUpdatedAt((($cron->getUpdatedAt() == null)? null : strtotime($cron->getUpdatedAt())));
|
53 |
+
}
|
54 |
+
}
|
app/code/community/Zero1/Crondoctor/README.md
ADDED
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<h1>Zero1 CronDoctor<h1><hr />
|
2 |
+
|
3 |
+
<h2>Install Instructions</h2>
|
4 |
+
<ol>
|
5 |
+
<li>Stop magento core cron, you can do this via either stop the crond service or simply commenting out the relative line in your cron tab</li>
|
6 |
+
<li>
|
7 |
+
wait for all cron processes to finish<br />
|
8 |
+
<pre>watch -n1 "ps aux | grep cron.php | grep -v grep"</pre><br />
|
9 |
+
</li>
|
10 |
+
<li>Install the module as normal, via FTP/Git/MCM</li>
|
11 |
+
<li>Flush both caches</li>
|
12 |
+
<li>
|
13 |
+
Alter the following configuration options:<br />
|
14 |
+
<ul>
|
15 |
+
<li>
|
16 |
+
System > Configuration > Advanced | System > Cron<br />
|
17 |
+
<ul>
|
18 |
+
<li>"Generate Schedules Every" = 15</li>
|
19 |
+
<li>"Schedule Ahead for" = 20</li>
|
20 |
+
<li>"Missed if Not Run Within" = 0</li>
|
21 |
+
<li>"History Cleanup Every" = [AS DESIRED]</li>
|
22 |
+
<li>"Success History Lifetime" = [AS DESIRED]</li>
|
23 |
+
<li>"Failure History Lifetime" = [AS DESIRED]</li>
|
24 |
+
</ul>
|
25 |
+
</li>
|
26 |
+
</ul>
|
27 |
+
</li>
|
28 |
+
<li>Alter your cron job to point to "zero1/cron.php", and restart crond if needed</li>
|
29 |
+
<li>
|
30 |
+
confirm jobs are running<br />
|
31 |
+
<pre>watch -n1 "ps aux | grep cron.php | grep -v grep"</pre><br />
|
32 |
+
on the minute you should see jobs ending with the following:<br />
|
33 |
+
<ul>
|
34 |
+
<li>-mdefault</li>
|
35 |
+
<li>-malways</li>
|
36 |
+
<li>-schedule</li>
|
37 |
+
<li>-zombie</li>
|
38 |
+
</ul>
|
39 |
+
</li>
|
40 |
+
</ol>
|
41 |
+
<hr />
|
42 |
+
<h2>Misc</h2>
|
43 |
+
<h3>Stopping/Starting Cron after installation</h3>
|
44 |
+
If you need to stop cron, from the root of your magento installation:<br />
|
45 |
+
<pre>touch zero1/cron_stop.flag</pre><br />
|
46 |
+
<pre>watch -n1 "ps aux | grep cron.php | grep -v grep"</pre><br />
|
47 |
+
wait until all jobs are finished.<br />
|
48 |
+
To restart cron:<br />
|
49 |
+
<pre>rm zero1/cron_stop.flag</pre><br />
|
50 |
+
you should then be able to see all jobs restarting
|
51 |
+
<hr />
|
52 |
+
<h3>Disaster Recover</h3>
|
53 |
+
If cron is stopped with the cron_stop.flag being in place, then you could end up with jobs the are permanently running.
|
54 |
+
This can be observed by going to System > Cron Doctor and checking filtering by status = 'running' if there are more than 2 jobs running there is an issue.<br />
|
55 |
+
<b>enterprise_refresh_index</b>: is an 'always' job, if this job hasn't ran since cron has been started again i.e status == running and executed_at is before cron was stopped, the status of this job will need changing (to anything but 'running')<br />
|
56 |
+
Every other job is the same principle as enterprise_refresh_index.
|
57 |
+
|
58 |
+
N.B you should expect 0 - 2 jobs running at anyone time if there are 2 jobs running 1 of them should be enterprise_refresh_index, if this is not the case there is an issue.
|
59 |
+
<hr />
|
app/code/community/Zero1/Crondoctor/controllers/Adminhtml/Crondoctor/VisualController.php
ADDED
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
class Zero1_Crondoctor_Adminhtml_CronDoctor_VisualController extends Mage_Adminhtml_Controller_Action
|
3 |
+
{
|
4 |
+
protected function _initAction()
|
5 |
+
{
|
6 |
+
$this->loadLayout()->_setActiveMenu('system/zero1_crondoctor');
|
7 |
+
$this->_title(Mage::helper('zero1_crondoctor')->__('Cron Doctor'));
|
8 |
+
|
9 |
+
return $this;
|
10 |
+
}
|
11 |
+
|
12 |
+
public function indexAction()
|
13 |
+
{
|
14 |
+
$this->_initAction()->renderLayout();
|
15 |
+
}
|
16 |
+
|
17 |
+
public function ajaxAction(){
|
18 |
+
|
19 |
+
$inputFrom = $this->getRequest()->getParam('from', time());
|
20 |
+
$inputTo = $this->getRequest()->getParam('to', time());
|
21 |
+
$visualType = $this->getRequest()->getParam('visual_type', 'stats');
|
22 |
+
|
23 |
+
$from = min((int)$inputFrom, (int)$inputTo);
|
24 |
+
$to = max((int)$inputTo, (int)$inputFrom);
|
25 |
+
|
26 |
+
$from = time() + (60 * 60 * $from);
|
27 |
+
$to = time() + (60 * 60 * $to);
|
28 |
+
|
29 |
+
echo 'From: '.strftime('%Y-%m-%d %H:%M:%S', $from).'<br />';
|
30 |
+
echo 'To: '.strftime('%Y-%m-%d %H:%M:%S', $to).'<br />';
|
31 |
+
|
32 |
+
|
33 |
+
switch($visualType){
|
34 |
+
case 'stats':
|
35 |
+
$orderBy = $this->getOrderBy($this->getRequest()->getParam('order_by', null));
|
36 |
+
$block = $this->getLayout()->createBlock('zero1_crondoctor/adminhtml_visual_visual');
|
37 |
+
$block->setFrom($from);
|
38 |
+
$block->setTo($to);
|
39 |
+
$block->setOrderBy($orderBy);
|
40 |
+
echo $block->toHtml();
|
41 |
+
break;
|
42 |
+
case 'lag':
|
43 |
+
$block = $this->getLayout()->createBlock('zero1_crondoctor/adminhtml_visual_lag');
|
44 |
+
$block->setFrom($from);
|
45 |
+
$block->setTo($to);
|
46 |
+
echo $block->toHtml();
|
47 |
+
break;
|
48 |
+
}
|
49 |
+
|
50 |
+
die;
|
51 |
+
}
|
52 |
+
|
53 |
+
private function getOrderBy($orderBy){
|
54 |
+
switch($orderBy){
|
55 |
+
case 'expected_runs':
|
56 |
+
default:
|
57 |
+
return 'expected_runs';
|
58 |
+
}
|
59 |
+
}
|
60 |
+
|
61 |
+
protected function _isAllowed()
|
62 |
+
{
|
63 |
+
return Mage::getSingleton('admin/session')->isAllowed('admin/system/zero1_crondoctor/zero1_crondoctor_visual');
|
64 |
+
}
|
65 |
+
}
|
app/code/community/Zero1/Crondoctor/controllers/Adminhtml/CrondoctorController.php
CHANGED
@@ -70,4 +70,9 @@ class Zero1_Crondoctor_Adminhtml_CrondoctorController extends Mage_Adminhtml_Con
|
|
70 |
|
71 |
$this->_redirect('*/*/index');
|
72 |
}
|
|
|
|
|
|
|
|
|
|
|
73 |
}
|
70 |
|
71 |
$this->_redirect('*/*/index');
|
72 |
}
|
73 |
+
|
74 |
+
protected function _isAllowed()
|
75 |
+
{
|
76 |
+
return Mage::getSingleton('admin/session')->isAllowed('admin/system/zero1_crondoctor');
|
77 |
+
}
|
78 |
}
|
app/code/community/Zero1/Crondoctor/etc/adminhtml.xml
CHANGED
@@ -6,6 +6,12 @@
|
|
6 |
<title>Cron Doctor</title>
|
7 |
<action>adminhtml/crondoctor</action>
|
8 |
<sort_order>99</sort_order>
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
</zero1_crondoctor>
|
10 |
</children>
|
11 |
</system>
|
@@ -19,6 +25,12 @@
|
|
19 |
<zero1_crondoctor translate="title" module="zero1_crondoctor">
|
20 |
<title>Cron Doctor</title>
|
21 |
<sort_order>99</sort_order>
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
</zero1_crondoctor>
|
23 |
|
24 |
<config>
|
6 |
<title>Cron Doctor</title>
|
7 |
<action>adminhtml/crondoctor</action>
|
8 |
<sort_order>99</sort_order>
|
9 |
+
<children>
|
10 |
+
<zero1_crondoctor_visual translate="title" module="zero1_crondoctor">
|
11 |
+
<title>Visual</title>
|
12 |
+
<action>adminhtml/crondoctor_visual</action>
|
13 |
+
</zero1_crondoctor_visual>
|
14 |
+
</children>
|
15 |
</zero1_crondoctor>
|
16 |
</children>
|
17 |
</system>
|
25 |
<zero1_crondoctor translate="title" module="zero1_crondoctor">
|
26 |
<title>Cron Doctor</title>
|
27 |
<sort_order>99</sort_order>
|
28 |
+
<children>
|
29 |
+
<zero1_crondoctor_visual translate="title" module="zero1_crondoctor">
|
30 |
+
<title>Visual</title>
|
31 |
+
<action>adminhtml/crondoctor_visual</action>
|
32 |
+
</zero1_crondoctor_visual>
|
33 |
+
</children>
|
34 |
</zero1_crondoctor>
|
35 |
|
36 |
<config>
|
app/code/community/Zero1/Crondoctor/etc/config.xml
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
<config>
|
3 |
<modules>
|
4 |
<Zero1_Crondoctor>
|
5 |
-
<version>1.0.
|
6 |
</Zero1_Crondoctor>
|
7 |
</modules>
|
8 |
|
@@ -27,6 +27,7 @@
|
|
27 |
<cron>
|
28 |
<rewrite>
|
29 |
<observer>Zero1_Crondoctor_Model_Observer</observer>
|
|
|
30 |
</rewrite>
|
31 |
</cron>
|
32 |
</models>
|
@@ -74,15 +75,41 @@
|
|
74 |
|
75 |
<crontab>
|
76 |
<jobs>
|
77 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
78 |
<schedule>
|
79 |
-
<
|
80 |
</schedule>
|
81 |
-
|
82 |
-
<model>zero1_crondoctor/observer::checkForZombieJobs</model>
|
83 |
-
</run>
|
84 |
-
</zero1_crondoctor_zombie_check>
|
85 |
</jobs>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
86 |
</crontab>
|
87 |
|
88 |
<default>
|
2 |
<config>
|
3 |
<modules>
|
4 |
<Zero1_Crondoctor>
|
5 |
+
<version>1.0.10</version>
|
6 |
</Zero1_Crondoctor>
|
7 |
</modules>
|
8 |
|
27 |
<cron>
|
28 |
<rewrite>
|
29 |
<observer>Zero1_Crondoctor_Model_Observer</observer>
|
30 |
+
<schedule>Zero1_Crondoctor_Model_Schedule</schedule>
|
31 |
</rewrite>
|
32 |
</cron>
|
33 |
</models>
|
75 |
|
76 |
<crontab>
|
77 |
<jobs>
|
78 |
+
<!--<zero1_crondoctor_zombie_check>-->
|
79 |
+
<!--<schedule>-->
|
80 |
+
<!--<cron_expr>* * * * *</cron_expr>-->
|
81 |
+
<!--</schedule>-->
|
82 |
+
<!--<run>-->
|
83 |
+
<!--<model>zero1_crondoctor/observer::checkForZombieJobs</model>-->
|
84 |
+
<!--</run>-->
|
85 |
+
<!--</zero1_crondoctor_zombie_check>-->
|
86 |
+
<!-- Job Expr Overrides -->
|
87 |
+
<M2ePro_cron>
|
88 |
<schedule>
|
89 |
+
<config_path>zero1_crondoctor/job_expr_overrides/m2epro_cron</config_path>
|
90 |
</schedule>
|
91 |
+
</M2ePro_cron>
|
|
|
|
|
|
|
92 |
</jobs>
|
93 |
+
<events>
|
94 |
+
<!-- Schedule Addition -->
|
95 |
+
<schedule>
|
96 |
+
<observers>
|
97 |
+
<cron_observer>
|
98 |
+
<class>cron/observer</class>
|
99 |
+
<method>schedule</method>
|
100 |
+
</cron_observer>
|
101 |
+
</observers>
|
102 |
+
</schedule>
|
103 |
+
<!-- Zombie Checker -->
|
104 |
+
<zombie>
|
105 |
+
<observers>
|
106 |
+
<cron_observer>
|
107 |
+
<class>zero1_crondoctor/observer_zombie</class>
|
108 |
+
<method>checkForZombieJobs</method>
|
109 |
+
</cron_observer>
|
110 |
+
</observers>
|
111 |
+
</zombie>
|
112 |
+
</events>
|
113 |
</crontab>
|
114 |
|
115 |
<default>
|
app/code/community/Zero1/Crondoctor/etc/system.xml
CHANGED
@@ -70,6 +70,25 @@
|
|
70 |
</developer_mode_jobs>
|
71 |
</fields>
|
72 |
</settings>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
73 |
</groups>
|
74 |
</zero1_crondoctor>
|
75 |
</sections>
|
70 |
</developer_mode_jobs>
|
71 |
</fields>
|
72 |
</settings>
|
73 |
+
<job_expr_overrides translate="label">
|
74 |
+
<label>Job Overrides</label>
|
75 |
+
<frontend_type>text</frontend_type>
|
76 |
+
<sort_order>2</sort_order>
|
77 |
+
<show_in_default>1</show_in_default>
|
78 |
+
<show_in_website>0</show_in_website>
|
79 |
+
<show_in_store>0</show_in_store>
|
80 |
+
<fields>
|
81 |
+
<m2epro_cron translate="label comment">
|
82 |
+
<label>M2ePro_cron</label>
|
83 |
+
<comment><![CDATA[If left blank, config xml value will be used.]]></comment>
|
84 |
+
<frontend_type>text</frontend_type>
|
85 |
+
<sort_order>1</sort_order>
|
86 |
+
<show_in_default>1</show_in_default>
|
87 |
+
<show_in_website>0</show_in_website>
|
88 |
+
<show_in_store>0</show_in_store>
|
89 |
+
</m2epro_cron>
|
90 |
+
</fields>
|
91 |
+
</job_expr_overrides>
|
92 |
</groups>
|
93 |
</zero1_crondoctor>
|
94 |
</sections>
|
app/code/community/Zero1/Crondoctor/sql/zero1_crondoctor_setup/upgrade-1.0.7-1.0.8.php
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/* @var $installer Mage_Core_Model_Resource_Setup */
|
3 |
+
$installer = $this;
|
4 |
+
$installer->startSetup();
|
5 |
+
|
6 |
+
/**
|
7 |
+
* Change columns
|
8 |
+
*/
|
9 |
+
$installer->getConnection()->addColumn(
|
10 |
+
$installer->getTable('cron/schedule'),
|
11 |
+
'updated_at',
|
12 |
+
array(
|
13 |
+
'type' => Varien_Db_Ddl_Table::TYPE_TIMESTAMP,
|
14 |
+
'nullable' => true,
|
15 |
+
'comment' => 'Updated At'
|
16 |
+
)
|
17 |
+
);
|
18 |
+
|
19 |
+
$installer->endSetup();
|
app/code/community/Zero1/Crondoctor/sql/zero1_crondoctor_setup/upgrade-1.0.8-1.0.9.php
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/* @var $installer Mage_Core_Model_Resource_Setup */
|
3 |
+
$installer = $this;
|
4 |
+
$installer->startSetup();
|
5 |
+
|
6 |
+
$installer->getConnection()->addColumn(
|
7 |
+
$installer->getTable('cron/schedule'),
|
8 |
+
'reported_at',
|
9 |
+
array(
|
10 |
+
'type' => Varien_Db_Ddl_Table::TYPE_TIMESTAMP,
|
11 |
+
'nullable' => true,
|
12 |
+
'comment' => 'Reported At'
|
13 |
+
)
|
14 |
+
);
|
15 |
+
|
16 |
+
$installer->endSetup();
|
app/design/adminhtml/default/default/layout/crondoctor/crondoctor.xml
CHANGED
@@ -11,4 +11,10 @@
|
|
11 |
<block type="zero1_crondoctor/adminhtml_crondoctor_notice" name="zero1_crondoctor_notice" template="crondoctor/notice.phtml" />
|
12 |
</reference>
|
13 |
</default>
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
</layout>
|
11 |
<block type="zero1_crondoctor/adminhtml_crondoctor_notice" name="zero1_crondoctor_notice" template="crondoctor/notice.phtml" />
|
12 |
</reference>
|
13 |
</default>
|
14 |
+
|
15 |
+
<adminhtml_crondoctor_visual_index>
|
16 |
+
<reference name="content">
|
17 |
+
<block type="zero1_crondoctor/adminhtml_visual" name="zero1_crondoctor_visual_container" />
|
18 |
+
</reference>
|
19 |
+
</adminhtml_crondoctor_visual_index>
|
20 |
</layout>
|
app/design/adminhtml/default/default/template/crondoctor/visual/container.phtml
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php /* @var $this Zero1_Crondoctor_Block_Adminhtml_Visual */
|
2 |
+
?>
|
3 |
+
<div class="content-header">
|
4 |
+
<table cellspacing="0">
|
5 |
+
<tr>
|
6 |
+
<td><h3><?php echo $this->getHeaderText() ?></h3></td>
|
7 |
+
<td class="form-buttons">
|
8 |
+
<?php echo $this->getButtonsHtml() ?>
|
9 |
+
</td>
|
10 |
+
</tr>
|
11 |
+
</table>
|
12 |
+
</div>
|
13 |
+
<?php echo $this->getFormHtml() ?>
|
14 |
+
<div id="visual-container"></div>
|
app/design/adminhtml/default/default/template/crondoctor/visual/visual.phtml
ADDED
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/* @var $this Zero1_Crondoctor_Block_Adminhtml_Visual_Visual */
|
3 |
+
/* @var $schedule Zero1_Crondoctor_Model_Schedule */
|
4 |
+
$schedule = $this->getSchedule();
|
5 |
+
$to = $this->getTo();
|
6 |
+
$from = $this->getFrom();
|
7 |
+
|
8 |
+
$defaultWidth = 1200;
|
9 |
+
$minMinuteDisplayWith = 12;
|
10 |
+
|
11 |
+
$diference = ($to - $from) / 60;
|
12 |
+
$diference -= ($diference % 60);
|
13 |
+
|
14 |
+
$naturalWidth = ($diference * $minMinuteDisplayWith);
|
15 |
+
$naturalWidth += 40; //padding for time display
|
16 |
+
/* @var $job Zero1_Crondoctor_Model_Schedule_Job */
|
17 |
+
/* @var $process Zero1_Crondoctor_Model_Schedule_Job_Process */
|
18 |
+
|
19 |
+
$jobHtml = array();
|
20 |
+
foreach($schedule->getSchedule() as $jobCode => $job){
|
21 |
+
list($html, $maxDepth) = $this->getJobHtml($job, $from, $naturalWidth);
|
22 |
+
$jobHtml[$jobCode] = array(
|
23 |
+
'html' => $html,
|
24 |
+
'max_depth' => $maxDepth,
|
25 |
+
);
|
26 |
+
}
|
27 |
+
|
28 |
+
|
29 |
+
?>
|
30 |
+
<div style="margin: 20px;">
|
31 |
+
<div style="float: left; padding: 40px 0 0 0; border: solid 1px #000000; border-right-width: 0; overflow: visible;">
|
32 |
+
<?php foreach($schedule->getSchedule() as $jobCode => $job): ?>
|
33 |
+
<div style="height: <?php echo $jobHtml[$jobCode]['max_depth'] * 10; ?>px; border-bottom: solid #000000 2px; background-color: orange; overflow: visible; padding: 0 10px;">
|
34 |
+
<?php echo $jobCode; ?><br />
|
35 |
+
(<?php echo $job->getCronExpr(); ?>)
|
36 |
+
</div>
|
37 |
+
<?php endforeach; ?>
|
38 |
+
</div>
|
39 |
+
<div style="float: left; border: solid 1px #000000;
|
40 |
+
width: <?php echo $defaultWidth; ?>px;
|
41 |
+
overflow-x: scroll;"
|
42 |
+
>
|
43 |
+
<div class="timebar" style="width: <?php echo $naturalWidth; ?>px;">
|
44 |
+
<div style="float: left; width: 40px; height: 40px; overflow: hidden;">
|
45 |
+
|
46 |
+
<div style="width: 40px; height: 20px; text-align: center;"><?php echo strftime('%H:%M', $from); ?></div>
|
47 |
+
<div style="float: left; width: 18px; height: 20px; border-right: solid; 2px #000000;"></div>
|
48 |
+
<div style="float: left; width: 18px; height: 20px; border-left: solid; 2px; #000000;"></div>
|
49 |
+
|
50 |
+
</div>
|
51 |
+
<?php
|
52 |
+
$oneHour = (60 * 60);
|
53 |
+
for($timeCount = ($from + $oneHour); $timeCount <= $to; $timeCount += $oneHour): ?>
|
54 |
+
<div style="float: left; width: <?php echo (($minMinuteDisplayWith * 60) - 40); ?>px; height: 40px;"></div>
|
55 |
+
|
56 |
+
<div style="float: left; width: 40px; height: 40px; overflow: hidden;">
|
57 |
+
|
58 |
+
<div style="width: 40px; height: 20px; text-align: center;"><?php echo strftime('%H:%M', $timeCount); ?></div>
|
59 |
+
<div style="float: left; width: 18px; height: 20px; border-right: solid #000000 2px;"></div>
|
60 |
+
<div style="float: left; width: 18px; height: 20px; border-left: solid #000000 2px;"></div>
|
61 |
+
|
62 |
+
</div>
|
63 |
+
<?php endfor; ?>
|
64 |
+
<div style="clear: both;"></div>
|
65 |
+
</div>
|
66 |
+
|
67 |
+
<?php foreach($schedule->getSchedule() as $jobCode => $job): ?>
|
68 |
+
<?php echo $jobHtml[$jobCode]['html']; ?>
|
69 |
+
<?php endforeach; ?>
|
70 |
+
</div>
|
71 |
+
<div style="float: left; padding: 40px 0 0 0; border: solid 1px #000000; border-left-width: 0; overflow: visible; width: 200px;">
|
72 |
+
<?php foreach($schedule->getSchedule() as $jobCode => $job): ?>
|
73 |
+
<div style="height: <?php echo $jobHtml[$jobCode]['max_depth'] * 10; ?>px; border-bottom: solid #000000 2px; overflow-y: scroll; padding: 0 10px;">
|
74 |
+
<?php foreach($job->getStats() as $key => $data): ?>
|
75 |
+
<?php echo $data['name'].': '.$data['value'].'<br />'; ?>
|
76 |
+
<?php //echo $data['description']; ?>
|
77 |
+
<?php endforeach; ?>
|
78 |
+
</div>
|
79 |
+
<?php endforeach; ?>
|
80 |
+
</div>
|
81 |
+
</div>
|
package.xml
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
<?xml version="1.0"?>
|
2 |
<package>
|
3 |
<name>Zero1_Crondoctor</name>
|
4 |
-
<version>1.0.
|
5 |
<stability>stable</stability>
|
6 |
<license uri="http://shop.zero1.co.uk/LICENSE.txt">Commercial</license>
|
7 |
<channel>community</channel>
|
@@ -9,11 +9,11 @@
|
|
9 |
<summary>Crondoctor</summary>
|
10 |
<description>Crondoctor
|
11 |
</description>
|
12 |
-
<notes>
|
13 |
<authors><author><name>Arron Moss</name><user>zero1limited</user><email>arron.moss@zero1.co.uk</email></author></authors>
|
14 |
-
<date>
|
15 |
-
<time>
|
16 |
-
<contents><target name="magecommunity"><dir name="Zero1"><dir name="Crondoctor"><dir name="Block"><dir name="Adminhtml"><dir name="Crondoctor"><file name="Grid.php" hash="ff758796ef8d66b388e0b1d60d73f92e"/><file name="Notice.php" hash="6b4c20f69f875fa3410a34acc8d2209a"/></dir><file name="Crondoctor.php" hash="6fa8fd6eee1dd35d9b82f861238738c1"/></dir></dir><dir name="Helper"><file name="Data.php" hash="4b85072f6909ba3f083c99814103a92a"/></dir><dir name="Model"><file name="Observer.php" hash="
|
17 |
<compatible/>
|
18 |
<dependencies><required><php><min>5.2.0</min><max>6.0.0</max></php></required></dependencies>
|
19 |
</package>
|
1 |
<?xml version="1.0"?>
|
2 |
<package>
|
3 |
<name>Zero1_Crondoctor</name>
|
4 |
+
<version>1.0.10</version>
|
5 |
<stability>stable</stability>
|
6 |
<license uri="http://shop.zero1.co.uk/LICENSE.txt">Commercial</license>
|
7 |
<channel>community</channel>
|
9 |
<summary>Crondoctor</summary>
|
10 |
<description>Crondoctor
|
11 |
</description>
|
12 |
+
<notes>ACL issue fix</notes>
|
13 |
<authors><author><name>Arron Moss</name><user>zero1limited</user><email>arron.moss@zero1.co.uk</email></author></authors>
|
14 |
+
<date>2016-03-08</date>
|
15 |
+
<time>09:28:41</time>
|
16 |
+
<contents><target name="magecommunity"><dir name="Zero1"><dir name="Crondoctor"><dir name="Block"><dir name="Adminhtml"><dir name="Crondoctor"><file name="Grid.php" hash="ff758796ef8d66b388e0b1d60d73f92e"/><file name="Notice.php" hash="6b4c20f69f875fa3410a34acc8d2209a"/></dir><file name="Crondoctor.php" hash="6fa8fd6eee1dd35d9b82f861238738c1"/><dir name="Visual"><file name="Form.php" hash="2df5703fc827781478fd07d1e28296a5"/><file name="Lag.php" hash="533573979e5c75c7f99b9a0a81cafbf1"/><file name="Visual.php" hash="48d7f42c7469621307134e864033ef1b"/></dir><file name="Visual.php" hash="2b2f08b18ca4c97716bfb9a3cb16c92c"/></dir></dir><dir name="Helper"><file name="Data.php" hash="4b85072f6909ba3f083c99814103a92a"/></dir><dir name="Model"><dir name="Observer"><file name="Zombie.php" hash="325e2b06c599fba12377f5be17738299"/></dir><file name="Observer.php" hash="be0e3653a5187ac5723386f6033f88a1"/><dir name="Schedule"><dir name="Job"><file name="Process.php" hash="57cf2b34b80024af1090e6f5e46c170f"/></dir><file name="Job.php" hash="2f2df91e0aa5f628aa196586d3d4c568"/></dir><file name="Schedule.php" hash="a3f86374eab1771d844a84c9184f3bbe"/><dir name="Visual"><dir name="Schedule"><dir name="Job"><file name="Process.php" hash="4d0b95ec31c3c7b7fcba86ff89159dc6"/></dir><file name="Job.php" hash="c2ea122f797ca735de59cfd1ff9bfc96"/></dir><file name="Schedule.php" hash="f5e4e64b1fe0ccb6bdd3ef380496e2b3"/></dir></dir><file name="README.md" hash="c1514c3ca5f67fefee310915c99e7772"/><dir name="controllers"><dir name="Adminhtml"><dir name="Crondoctor"><file name="VisualController.php" hash="935cb373b65cc193cb6740ab4a140495"/></dir><file name="CrondoctorController.php" hash="fef96b78d8443ed6494a3b19affed8ec"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="b32ed969146550cc2a98d4b133eb4543"/><file name="config.xml" hash="30009266047b8057de21eba9e7de1ab1"/><file name="system.xml" hash="b6251a8f7b3ff0a63241d6d421e59eaf"/></dir><dir name="sql"><dir name="zero1_crondoctor_setup"><file name="install-1.0.0.php" hash="af6b55e68b5c327efcf58452719d359e"/><file name="mysql4-install-1.0.0.php" hash="af6b55e68b5c327efcf58452719d359e"/><file name="upgrade-1.0.7-1.0.8.php" hash="4431ab57cc541f82a75734eefa8e494a"/><file name="upgrade-1.0.8-1.0.9.php" hash="a72fda900430ce3cde8cc6e636138ecb"/></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Zero1_Crondoctor.xml" hash="3ccefc4ae6efeecc2bfd7df6a59264f1"/></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><dir name="crondoctor"><file name="crondoctor.xml" hash="3ec02e0cf305a7bd347c78a8420e799f"/></dir></dir><dir name="template"><dir name="crondoctor"><file name="notice.phtml" hash="95575d8f09e623c05c0de950677346ce"/><dir name="visual"><file name="container.phtml" hash="5242e2d186173d5b3bf779b1f14024c8"/><file name="visual.phtml" hash="d9f16c4ac6d847846335b494b39c0169"/></dir></dir></dir></dir></dir></dir></target><target name="magelocale"><dir name="en_US"><dir name="template"><dir name="email"><file name="crondoctor_zombieemail.html" hash="ad7b0695ba42ddaea95e50b8d9859370"/></dir></dir></dir></target><target name="mage"><dir name="zero1"><file name="cron.php" hash="dc8160c75340b38bc5b1554d7a0bf0e2"/><file name="cron.sh" hash="c752a6d282579c3f2ed2e7a2e5864f28"/></dir></target></contents>
|
17 |
<compatible/>
|
18 |
<dependencies><required><php><min>5.2.0</min><max>6.0.0</max></php></required></dependencies>
|
19 |
</package>
|
zero1/cron.php
ADDED
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Magento Enterprise Edition
|
4 |
+
*
|
5 |
+
* NOTICE OF LICENSE
|
6 |
+
*
|
7 |
+
* This source file is subject to the Magento Enterprise Edition License
|
8 |
+
* that is bundled with this package in the file LICENSE_EE.txt.
|
9 |
+
* It is also available through the world-wide-web at this URL:
|
10 |
+
* http://www.magentocommerce.com/license/enterprise-edition
|
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@magentocommerce.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.magentocommerce.com for more information.
|
20 |
+
*
|
21 |
+
* @category Mage
|
22 |
+
* @package Mage
|
23 |
+
* @copyright Copyright (c) 2013 Magento Inc. (http://www.magentocommerce.com)
|
24 |
+
* @license http://www.magentocommerce.com/license/enterprise-edition
|
25 |
+
*/
|
26 |
+
|
27 |
+
// Change current directory to the directory of current script
|
28 |
+
chdir(dirname(__FILE__));
|
29 |
+
|
30 |
+
require '../app/Mage.php';
|
31 |
+
|
32 |
+
if (!Mage::isInstalled()) {
|
33 |
+
echo "Application is not installed yet, please complete install wizard first.";
|
34 |
+
exit;
|
35 |
+
}
|
36 |
+
|
37 |
+
// Only for urls
|
38 |
+
// Don't remove this
|
39 |
+
$_SERVER['SCRIPT_NAME'] = str_replace(basename(__FILE__), 'index.php', $_SERVER['SCRIPT_NAME']);
|
40 |
+
$_SERVER['SCRIPT_FILENAME'] = str_replace(basename(__FILE__), 'index.php', $_SERVER['SCRIPT_FILENAME']);
|
41 |
+
|
42 |
+
Mage::app('admin')->setUseSessionInUrl(false);
|
43 |
+
|
44 |
+
if(Zero1_Crondoctor_Model_Observer::shouldStop()){
|
45 |
+
echo 'Stop Flag Found'.PHP_EOL;
|
46 |
+
exit;
|
47 |
+
}
|
48 |
+
|
49 |
+
umask(0);
|
50 |
+
|
51 |
+
$disabledFuncs = explode(',', ini_get('disable_functions'));
|
52 |
+
$isShellDisabled = is_array($disabledFuncs) ? in_array('shell_exec', $disabledFuncs) : true;
|
53 |
+
$isShellDisabled = (stripos(PHP_OS, 'win') === false) ? $isShellDisabled : true;
|
54 |
+
|
55 |
+
$cronModes = array(
|
56 |
+
'always' => 'always',
|
57 |
+
'default' => 'default',
|
58 |
+
'schedule' => 'schedule',
|
59 |
+
'zombie' => 'zombie',
|
60 |
+
);
|
61 |
+
|
62 |
+
try {
|
63 |
+
if (stripos(PHP_OS, 'win') === false) {
|
64 |
+
$options = getopt('m::');
|
65 |
+
if (isset($options['m'])) {
|
66 |
+
|
67 |
+
if(isset($cronModes[$options['m']])){
|
68 |
+
$cronMode = $cronModes[$options['m']];
|
69 |
+
}else{
|
70 |
+
Mage::throwException('Unrecognized cron mode was defined');
|
71 |
+
}
|
72 |
+
|
73 |
+
} else if (!$isShellDisabled) {
|
74 |
+
$fileName = basename(__FILE__);
|
75 |
+
$baseDir = dirname(__FILE__);
|
76 |
+
|
77 |
+
foreach($cronModes as $key => $mode){
|
78 |
+
shell_exec("/bin/sh $baseDir/cron.sh $fileName -m".$key." 1 > /dev/null 2>&1 &");
|
79 |
+
}
|
80 |
+
exit;
|
81 |
+
}
|
82 |
+
}
|
83 |
+
|
84 |
+
Mage::getConfig()->init()->loadEventObservers('crontab');
|
85 |
+
Mage::app()->addEventArea('crontab');
|
86 |
+
if ($isShellDisabled) {
|
87 |
+
Mage::dispatchEvent('always');
|
88 |
+
Mage::dispatchEvent('default');
|
89 |
+
} else {
|
90 |
+
Mage::dispatchEvent($cronMode);
|
91 |
+
}
|
92 |
+
} catch (Exception $e) {
|
93 |
+
Mage::printException($e);
|
94 |
+
exit(1);
|
95 |
+
}
|
zero1/cron.sh
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/bin/sh
|
2 |
+
# location of the php binary
|
3 |
+
if [ ! "$1" = "" ] ; then
|
4 |
+
CRONSCRIPT=$1
|
5 |
+
else
|
6 |
+
CRONSCRIPT=cron.php
|
7 |
+
fi
|
8 |
+
|
9 |
+
MODE=""
|
10 |
+
if [ ! "$2" = "" ] ; then
|
11 |
+
MODE=" $2"
|
12 |
+
fi
|
13 |
+
|
14 |
+
PHP_BIN=`which php`
|
15 |
+
|
16 |
+
# absolute path to magento installation
|
17 |
+
INSTALLDIR=`echo $0 | sed 's/cron\.sh//g'`
|
18 |
+
|
19 |
+
# prepend the intallation path if not given an absolute path
|
20 |
+
if [ "$INSTALLDIR" != "" -a "`expr index $CRONSCRIPT /`" != "1" ];then
|
21 |
+
if ! ps auxwww | grep "$INSTALLDIR$CRONSCRIPT$MODE" | grep -v grep 1>/dev/null 2>/dev/null ; then
|
22 |
+
$PHP_BIN $INSTALLDIR$CRONSCRIPT$MODE &
|
23 |
+
fi
|
24 |
+
else
|
25 |
+
if ! ps auxwww | grep "$CRONSCRIPT$MODE" | grep -v grep | grep -v cron.sh 1>/dev/null 2>/dev/null ; then
|
26 |
+
$PHP_BIN $CRONSCRIPT$MODE &
|
27 |
+
fi
|
28 |
+
fi
|