188 lines
5.6 KiB
PHP
188 lines
5.6 KiB
PHP
<?php
|
|
|
|
class Crunchbutton_Cron_Log extends Cana_Table {
|
|
|
|
const INTERVAL_MINUTE = 'minute';
|
|
const INTERVAL_DAY = 'day';
|
|
const INTERVAL_WEEK = 'week';
|
|
const INTERVAL_MONTH = 'month';
|
|
const INTERVAL_YEAR = 'year';
|
|
|
|
const CURRENT_STATUS_IDLE = 'idle';
|
|
const CURRENT_STATUS_RUNNING = 'running';
|
|
|
|
const LAST_STATUS_ERROR = 'error';
|
|
const LAST_STATUS_SUCCESS = 'success';
|
|
|
|
public function __construct($id = null) {
|
|
parent::__construct();
|
|
$this->table('cron_log')->idVar('id_cron_log')->load($id);
|
|
}
|
|
|
|
// start all the crons
|
|
public static function start(){
|
|
$crons = Crunchbutton_Cron_Log::q( "SELECT * FROM cron_log WHERE `interval` != '' AND interval_unity > 0" );
|
|
if( $crons->count() ){
|
|
Log::debug( [ 'type' => 'cron-jobs', 'method' => 'start', 'desc' => 'working with ' . $crons->count() . ' cron jobs' ] );
|
|
foreach( $crons as $cron ){
|
|
if( $cron->should_start() ){
|
|
$cron->que();
|
|
}
|
|
}
|
|
} else {
|
|
Log::debug( [ 'type' => 'cron-jobs', 'method' => 'start', 'desc' => 'there is no cron jobs to run' ] );
|
|
}
|
|
}
|
|
|
|
public function que(){
|
|
|
|
if( $this->update_next_time() ){
|
|
|
|
$this->log( 'que', 'starting que' );
|
|
$this->current_status = Crunchbutton_Cron_Log::CURRENT_STATUS_RUNNING;
|
|
$this->save();
|
|
|
|
$job = $this;
|
|
|
|
// Timeout to run it async
|
|
Cana::timeout( function() use( $job ) {
|
|
$job->go();
|
|
} );
|
|
}
|
|
}
|
|
|
|
public function should_start(){
|
|
|
|
if( !$this->start_date() ){
|
|
$this->log( 'should_start', 'job doesnt have start date' );
|
|
}
|
|
|
|
// now
|
|
$now = new DateTime( 'now', new DateTimeZone( c::config()->timezone ) );
|
|
|
|
// if it didn't have a next time it might be the first time it is running
|
|
if( !$this->next_time() ){
|
|
if( !$this->update_next_time() ){
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if( $now > $this->next_time( true ) ){
|
|
// make sure it is not running
|
|
if( $this->current_status != Crunchbutton_Cron_Log::CURRENT_STATUS_RUNNING ){
|
|
return true;
|
|
} else {
|
|
// if it is time to run again and the last job didn't finished, some problem occurred
|
|
$this->error_warning();
|
|
return true;
|
|
}
|
|
}
|
|
$this->log( 'should_start', 'not this time: ' . $this->next_time( true )->format( 'Y-m-d H:i:s' ) );
|
|
return false;
|
|
}
|
|
|
|
|
|
public function update_next_time(){
|
|
|
|
$now = new DateTime( 'now', new DateTimeZone( c::config()->timezone ) );
|
|
|
|
$date = ( $this->next_time() ) ? $this->next_time() : $this->start_date();
|
|
|
|
$watch_dog = 1;
|
|
|
|
if( $date < $now ){
|
|
$next_time = $date->modify( '+ ' . ( $this->interval_unity ) . ' ' . ( $this->interval ) );
|
|
while ( $now > $next_time ) {
|
|
$next_time = $date->modify( '+ ' . ( $this->interval_unity ) . ' ' . ( $this->interval ) );
|
|
$watch_dog++;
|
|
if( $watch_dog >= 10000 ){
|
|
$message = 'The cron task "' . $this->description . '" have a problem updating the next_time and didn\'t run. If you get this message tell it to the devs. Thank you.';
|
|
Crunchbutton_Support::createNewWarning( [ 'body' => $message ] );
|
|
$this->log( 'update_next_time', 'watch_dog:' . $watch_dog . ' next_time: ' . $next_time->format( 'Y-m-d H:i:s' ) );
|
|
return false;
|
|
}
|
|
}
|
|
} else {
|
|
$next_time = $date;
|
|
}
|
|
|
|
$this->log( 'update_next_time', 'watch_dog:' . $watch_dog . ' next_time: ' . $next_time->format( 'Y-m-d H:i:s' ) );
|
|
|
|
$this->next_time = $next_time->format( 'Y-m-d H:i:s' );
|
|
$this->save();
|
|
|
|
return true;
|
|
}
|
|
|
|
public function error_warning(){
|
|
|
|
// Create a support ticket
|
|
$last_time_it_started = $this->next_time();
|
|
$message = 'The cron task "' . $this->description . '" started running at ' . $last_time_it_started->format('M jS Y g:i:s A') . ' and didn`t finish yet.' . "\n" . 'Please check it, it seems an error has occurred.';
|
|
Crunchbutton_Support::createNewWarning( [ 'body' => $message ] );
|
|
|
|
$this->log( 'error_warning', 'message:' . $message );
|
|
|
|
// change the current status to let it start
|
|
$this->status = Crunchbutton_Cron_Log::CURRENT_STATUS_IDLE;
|
|
$this->save();
|
|
}
|
|
|
|
public function go(){
|
|
if( class_exists( $this->class ) ){
|
|
$job = new $this->class;
|
|
if( is_a( $job, 'Crunchbutton_Cron_Log' ) ){
|
|
if( method_exists( $job, 'run' ) ){
|
|
$this->log( 'run', 'running' );
|
|
$job->id_cron_log = $this->id_cron_log;
|
|
$job->run();
|
|
} else {
|
|
$this->log( 'run', 'error: ' . $this->class . ' doesnt have the method run' );
|
|
}
|
|
} else {
|
|
$this->log( 'run', 'error: ' . $this->class . ' isnt instance of Crunchbutton_Cron_Log' );
|
|
}
|
|
} else {
|
|
$this->log( 'run', 'error: ' . $this->class . ' doesnt exist' );
|
|
}
|
|
}
|
|
|
|
// called when the cron finish running
|
|
public function finished(){
|
|
|
|
$job = Crunchbutton_Cron_Log::o( $this->id_cron_log );
|
|
$job->log( 'finished', 'the interaction ' . $job->interactions );
|
|
|
|
$job->finished = date('Y-m-d H:i:s');
|
|
$job->interactions = ( !$job->interactions ? 1 : $job->interactions + 1 );
|
|
$job->current_status = Crunchbutton_Cron_Log::CURRENT_STATUS_IDLE;
|
|
$job->save();
|
|
}
|
|
|
|
public function start_date() {
|
|
if( $this->start_date ){
|
|
if ( !isset( $this->_start_date ) ){
|
|
$this->_start_date = new DateTime( $this->start_date, new DateTimeZone( c::config()->timezone ) );
|
|
}
|
|
return $this->_start_date;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public function next_time( $force = false ){
|
|
if( $force ){ unset( $this->_next_time ); }
|
|
if( $this->next_time ){
|
|
if ( !isset( $this->_next_time ) ){
|
|
$this->_next_time = new DateTime( $this->next_time, new DateTimeZone( c::config()->timezone ) );
|
|
}
|
|
return $this->_next_time;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public function log( $method, $message ){
|
|
$data = [ 'type' => 'cron-jobs', 'method' => $method, 'message' => $message, 'desc' => $this->description, 'id_cron_log' => $this->id_cron_log ];
|
|
Log::debug( $data );
|
|
}
|
|
|
|
} |