Current File : /pages/54/47/d0016649/home/htdocs/ob_maxi/wp-content/plugins/digimember/system/model/job/base.php
<?php

abstract class ncore_BaseJob extends ncore_Model
{
    const lock_timeout_seconds = 3600;

    public function cronMinutely() {

        if (!$this->canRun())
        {
            return;
        }

        $this->model()->fixCrashedJobs();

        $this->runJobs();

        $this->abortJobs();
    }

    public function jobStatusse() {

        return array(
            NCORE_JOB_STATUS_CREATED   => _ncore( 'New' ),
            NCORE_JOB_STATUS_PENDING   => _ncore( 'Waiting ...' ),
            NCORE_JOB_STATUS_RUNNING   => _ncore( 'Running ...' ),
            NCORE_JOB_STATUS_ABORTING  => _ncore( 'Aborting ...' ),
            NCORE_JOB_STATUS_COMPLETE  => _ncore( 'Finished' ),
        );
    }

    public function jobResults() {
        return array(
            NCORE_RESULT_SUCCESS => _ncore( 'Success' ),
            NCORE_RESULT_ABORTED => _ncore( 'Aborted' ),
            NCORE_RESULT_ERROR   => _ncore( 'Error!' ),
            NCORE_RESULT_UNKNOWN => _ncore( 'Running' ),
        );
    }

    public function jobResultsCss() {
        return array(
            NCORE_RESULT_SUCCESS => 'ncore_msg ncore_msg_success ncore_plain',
            NCORE_RESULT_ABORTED => 'ncore_msg ncore_msg_error ncore_plain',
            NCORE_RESULT_ERROR   => 'ncore_msg ncore_msg_error ncore_plain',
            NCORE_RESULT_UNKNOWN => 'ncore_msg ncore_msg_error ncore_plain',
        );
    }

    public function jobResultsWithCss() {

        $results = array();

        $css = $this->jobResultsCss();

        foreach ($this->jobResults() as $result => $label) {
            $class = $css[ $result ];
            $results[ $result ] = "<span class='$class'>$label</span>";
        }

        return $results;
    }

    //
    // protected
    //
    abstract protected function model();

    abstract protected function computePercentDone( $job );

    protected function canRun()
    {
        return true;
    }

    protected function startJob( $data=array(), $where=array(), $order_by = 'modified ASC' ) {

        $model = $this->model();

        $where[ 'status' ] = NCORE_JOB_STATUS_PENDING;
        $where[ 'locked' ] = null;

        $data['locked']             = ncore_dbDate();
        $data['current_perc_done']  = 0.1;
        $data['current_start_time'] = ncore_dbDate();

        $all = $model->getAll( $where, $limit=false, $order_by );

        foreach ($all as $job) {

            $locked = $model->changeStatus( $job->id, $by='system', NCORE_JOB_STATUS_RUNNING, $data, $where );

            if ($locked) {
                foreach ($data as $key => $value)
                {
                    $job->$key = $value;
                }
                return $job;
            }
        }

        return false;
    }

    protected function resumeJob()
    {

        $model = $this->model();

        $where = array( 'status' => NCORE_JOB_STATUS_RUNNING, 'locked' => null );
        $limit    = '';
        $order_by = 'modified ASC';

        $data = array();
        $data['locked'] = ncore_dbDate();

        $all = $model->getAll( $where, $limit, $order_by );

        foreach ($all as $job) {
            $locked = $model->update( $job->id, $data );
            if ($locked) {
                return $job;
            }
        }

        return false;
    }

    protected function finishJob( $job, $result, $next_status=NCORE_JOB_STATUS_COMPLETE,  $data=array() )
    {
        $model = $this->model();

        $start_time_unix = strtotime( $job->current_start_time );

        $data['last_run']    = ncore_dbDate();
        $data['last_result'] = $result;
        $data['locked']      = null;

        $data['current_start_time']  = null;
        $data['current_perc_done']   = 100;

        $model->changeStatus( $job->id, $by='system', $next_status, $data );

        $run_time_msg = '';
        if ($start_time_unix)
        {
            $this->api->load->helper( 'date' );
            $run_time_unix = ncore_serverTime() - $start_time_unix;
            $run_time_disp = ncore_formatTimeSpan( $run_time_unix, 'timespan' );

            $run_time_msg = ' (' . _ncore( 'run time: %s', $run_time_disp ) . ')';
        }


        switch ($result)
        {
            case NCORE_RESULT_SUCCESS:
                $this->success( $job, _ncore( 'Successfully completed' ) .  $run_time_msg );
                break;

            default;
                $this->error( $job, _ncore( 'Completed with errors' ) .  $run_time_msg );
        }
    }

    protected function touchJob( $job, $data=array() )
    {
        $this->computePercentDone( $job );

        $data['current_perc_done']   = $job->current_perc_done;

        $model = $this->model();

        $model->update( $job->id, $data );
    }

    abstract protected function processJob( $job );

    protected function error( $job, $msg ) {

        $section = $this->encode_log_id( $job );

        $this->log()->log( 'error', $section, $msg );
    }

    protected function warning( $job, $msg ) {

        $section = $this->encode_log_id( $job );

        $this->log()->log( 'warning', $section, $msg );
    }

    protected function success( $job, $msg ) {

        $section = $this->encode_log_id( $job );

        $this->log()->log( 'info', $section, $msg );
    }

    //
    // private
    //
    private $log;
    private function log() {
        if (!isset( $this->log)) {
            $this->log = $this->api->load->model( 'data/backup_log' );
        }
        return $this->log;
    }

    private function maxConcurrentJobCount() {

        $config = $this->api->load->model( 'logic/network_config' );
        $concurrent_job_count = $config->get( 'concurrent_job_count', 3 );

        return $concurrent_job_count;
    }

    private function runningJobCount()
    {
        $model1 = $this->api->load->model( 'data/job' );
        $model2 = $this->api->load->model( 'data/snapshot' );

        return $model1->runningJobCount() + $model2->runningJobCount();
    }

    private function runJobs()
    {
        $job = false;

        while (ncore_cronMayContinue())
        {
            if (!$job) {
                $job = $this->resumeJob();
            }
            if (!$job) {

                $max_concurrent_job_count = $this->maxConcurrentJobCount();

                $job_count = $this->runningJobCount();
                if ($job_count > $max_concurrent_job_count) {
                    break;
                }

                $job = $this->startJob();
            }
            if (!$job) {
                break;
            }

            list( $finished,
                  $result ) = $this->processJob( $job );

            if ($finished) {
                $this->finishJob( $job, $result );
                $job = false;
            }
        }

        if ($job) {
            $this->unlockJob( $job );
        }
    }

    private function abortJobs() {

        $model = $this->model();

        $where = array(
            'status' => NCORE_JOB_STATUS_ABORTING,
            'locked' => null,
        );
        $all = $model->getAll( $where );
        foreach ($all as $one) {
            $this->warning( $one, _ncore( 'Aborted on user request.' ) );
            $this->finishJob( $one, NCORE_RESULT_ABORTED );
        }


        $lock_timed_out_at = ncore_serverTime() - self::lock_timeout_seconds;
        $where = array(
            'locked <' => ncore_dbDate( $lock_timed_out_at ),
        );
        $all = $model->getAll( $where );
        foreach ($all as $one) {
            $this->warning( $one, _ncore( 'Job crashed! Job now resetted.' ) );
            $this->finishJob( $one, NCORE_RESULT_ABORTED );
        }
    }


    private function encode_log_id( $job )
    {
        return $job->table . '_' . $job->id;
    }

    private function unlockJob( $job )
    {
        $data = array();
        $data['locked'] = null;

        $this->touchJob( $job, $data );
    }

}