From c40ee917df41f3a146513071abe7ff80cb6d292e Mon Sep 17 00:00:00 2001 From: Paolo Date: Tue, 23 Jun 2026 14:59:34 +0200 Subject: [PATCH] Refactored main components --- .../controllers/jobs/LongRunTaskExecJob.php | 45 +++++-- application/controllers/lrts/LRTDummy.php | 117 ++++++++--------- application/core/LRT_Controller.php | 29 +---- application/libraries/LongRunTaskLib.php | 119 ++++++++++++++++-- 4 files changed, 209 insertions(+), 101 deletions(-) diff --git a/application/controllers/jobs/LongRunTaskExecJob.php b/application/controllers/jobs/LongRunTaskExecJob.php index 3541876de..aeb62eb04 100644 --- a/application/controllers/jobs/LongRunTaskExecJob.php +++ b/application/controllers/jobs/LongRunTaskExecJob.php @@ -38,7 +38,8 @@ class LongRunTaskExecJob extends JOB_Controller $this->logInfo('Execute long run tasks started'); // Get all the LRTs that is possible to execute now - $lrtsResult = $this->longruntasklib->getLRTs(); + $lrtsResult = $this->longruntasklib->getNewLRTs(); + // If an error occurred then return it if (isError($lrtsResult)) return $lrtsResult; if (hasData($lrtsResult)) @@ -47,7 +48,8 @@ class LongRunTaskExecJob extends JOB_Controller foreach (getData($lrtsResult) as $lrt) { // Execute the task - $this->longruntasklib->executeLrt($lrt); + $executeLrtResult = $this->longruntasklib->executeLrt($lrt); + if (isError($executeLrtResult)) $this->logError($executeLrtResult); } } @@ -55,7 +57,7 @@ class LongRunTaskExecJob extends JOB_Controller } /** - * + * Kills all the hanging LRTs */ public function killHangingLRTs() { @@ -63,6 +65,7 @@ class LongRunTaskExecJob extends JOB_Controller // Get all the LRTs that is possible to execute now $lrtsResult = $this->longruntasklib->getHangingLRTs(); + // If an error occurred then return it if (isError($lrtsResult)) return $lrtsResult; if (hasData($lrtsResult)) @@ -70,16 +73,40 @@ class LongRunTaskExecJob extends JOB_Controller // For each LRT foreach (getData($lrtsResult) as $lrt) { - // Kill the process with a SIGKILL - exec('kill -9 '.$lrt->pid.' > /dev/null 2>&1'); - - // Set the LRT as failed - $lrtExecFailedResult = $this->longruntasklib->lrtExecFailed($lrt->jobid); - if (isError($lrtExecFailedResult)) $this->logError(getError(lrtExecFailedResult)); + // Kill the task + $killLrtResult = $this->longruntasklib->killLrt($lrt); + if (isError($killLrtResult)) $this->logError($killLrtResult); } } $this->logInfo('Kill hanging LRTs ended'); } + + /** + * + */ + public function checkExecution() + { + $this->logInfo('Check execution long run tasks started'); + + // Get the related LRT data from the queue + $lrtsResult = $this->longruntasklib->getRunningLRTs(); + // If an error occurred then return it + if (isError($lrtsResult)) return $lrtsResult; + + // If there are running LRTs + if (hasData($lrtsResult)) + { + // For each LRT + foreach (getData($lrtsResult) as $lrt) + { + // Check the LRT execution + $checkExecutionResult = $this->longruntasklib->checkExecution($lrt); + if (isError($checkExecutionResult)) $this->logError($checkExecutionResult); + } + } + + $this->logInfo('Check execution long run tasks ended'); + } } diff --git a/application/controllers/lrts/LRTDummy.php b/application/controllers/lrts/LRTDummy.php index cb918ee62..45c3e1c2f 100644 --- a/application/controllers/lrts/LRTDummy.php +++ b/application/controllers/lrts/LRTDummy.php @@ -9,69 +9,74 @@ if (!defined("BASEPATH")) exit("No direct script access allowed"); class LRTDummy extends LRT_Controller { /** - * Loops on the number of seconds provided by the LRT input - * Sleeps every time 1 sec - * Writes the progress - * Writes the output + * This method must be implemented! */ public function run($jobid) { $this->logInfo('Long run tasks '.get_class($this).' started'); - $this->_jobid = $jobid; - - // Get the LRT record related to the provided jobid - $lrtResult = $this->getLrt(); - - // If an error occurred or the record has not been found - if (isError($lrtResult) || !hasData($lrtResult)) - { - $this->logError($lrtResult); - } - else - { - // Get the record - $lrt = getData($lrtResult)[0]; - - // Get and check the input - $input = json_decode($lrt->input); - if ($input == null) - { - $this->logError('LRT input is not a valid json'); - } - else - { - $error = false; // be optimistic - - // Operation - for ($i = 0; $i < (int)$input->sleep; $i++) - { - sleep(1); - // Set the progress - $setProgressResult = $this->setProgress((($i + 1) / (int)$input->sleep) * 100); - if (isError($setProgressResult)) - { - $this->logError($setProgressResult); - $error = true; - } - } - - // If no errors - if (!$error) - { - $this->logInfo('The user '.$lrt->uid.' slept for '.$input->sleep.' seconds'); - - // Set the output - $setOutputResult = $this->setOutput('The user '.$lrt->uid.' slept for '.$input->sleep.' seconds'); - if (isError($setOutputResult)) - { - $this->logError($setOutputResult); - } - } - } - } + $this->_doIt($jobid); $this->logInfo('Long run tasks '.get_class($this).' ended'); } + + /** + * Loops on the number of seconds provided by the LRT input + * Sleeps every time 1 sec + * Writes the progress + * Writes the output + */ + private function _doIt($jobid) + { + // Get the LRT record related to the provided jobid + $lrtResult = $this->getLrt($jobid); + + // If an error occurred or the record has not been found + if (isError($lrtResult)) + { + $this->logError($lrtResult); + return; + } + if (!hasData($lrtResult)) + { + $this->logError('LRT not found in database'); + return; + } + + // Get the record + $lrt = getData($lrtResult)[0]; + + // Get and check the input + $input = json_decode($lrt->{LongRunTaskLib::PROPERTY_INPUT}); + if ($input == null) + { + $this->logError('LRT input is not a valid json'); + return; + } + + // Operation + for ($i = 0; $i < (int)$input->sleep; $i++) + { + sleep(1); + // Set the progress + $setProgressResult = $this->setProgress($jobid, (($i + 1) / (int)$input->sleep) * 100); + if (isError($setProgressResult)) + { + $this->logError($setProgressResult); + return; + } + } + + $sleepMsg = 'The user '.$lrt->{LongRunTaskLib::PROPERTY_UID}.' slept for '.$input->sleep.' seconds'; + + $this->logInfo($sleepMsg); + + // Set the output + $setOutputResult = $this->setOutput($jobid, $sleepMsg); + if (isError($setOutputResult)) + { + $this->logError($setOutputResult); + } + } } diff --git a/application/core/LRT_Controller.php b/application/core/LRT_Controller.php index fe964945c..cde2fc485 100644 --- a/application/core/LRT_Controller.php +++ b/application/core/LRT_Controller.php @@ -15,8 +15,6 @@ if (!defined("BASEPATH")) exit("No direct script access allowed"); */ abstract class LRT_Controller extends JOB_Controller { - protected $_jobid; // record id for this LRT - /** * Constructor */ @@ -34,21 +32,6 @@ abstract class LRT_Controller extends JOB_Controller // Loads LongRunTaskLib library $this->load->library('LongRunTaskLib'); - - $this->_jobid = null; // default value - } - - /** - * Destructor, once the LRT execution is over... - */ - public function __destruct() - { - // Sends email to the user - - // Set the status and the endtime of this LRT as done - $lrtExecOverResult = $this->longruntasklib->lrtExecOver($this->_jobid); - // If an error occurred then log it - if (isError($lrtExecOverResult)) $this->logError($lrtExecOverResult); } //------------------------------------------------------------------------------------------------------------------ @@ -62,25 +45,25 @@ abstract class LRT_Controller extends JOB_Controller /** * */ - protected function getLrt() + protected function getLrt($jobid) { - return $this->longruntasklib->getLrt($this->_jobid); + return $this->longruntasklib->getLrt($jobid); } /** * */ - protected function setProgress($progress) + protected function setProgress($jobid, $progress) { - return $this->longruntasklib->setProgress($this->_jobid, $progress); + return $this->longruntasklib->setProgress($jobid, $progress); } /** * */ - protected function setOutput($output) + protected function setOutput($jobid, $output) { - return $this->longruntasklib->setOutuput($this->_jobid, $output); + return $this->longruntasklib->setOutuput($jobid, $output); } } diff --git a/application/libraries/LongRunTaskLib.php b/application/libraries/LongRunTaskLib.php index 46e1f5a97..feb463d7f 100644 --- a/application/libraries/LongRunTaskLib.php +++ b/application/libraries/LongRunTaskLib.php @@ -17,6 +17,7 @@ class LongRunTaskLib extends JobsQueueLib // LRT object properties const PROPERTY_UID = 'uid'; + const PROPERTY_PID = 'pid'; /** * Constructor @@ -37,7 +38,7 @@ class LongRunTaskLib extends JobsQueueLib * The maximum number of returned queued LRTs is limited by: * number of currently running LRTs - maximum allowed number of LRTs for the system */ - public function getLRTs() + public function getNewLRTs() { // Get all the running LRTs $runningLrtsResult = $this->getJobsByTypeStatus($this->_ci->config->item(self::CFG_LRT_TYPES), JobsQueueLib::STATUS_RUNNING); @@ -71,6 +72,25 @@ class LongRunTaskLib extends JobsQueueLib ); } + /** + * Get all the LRT that are currently running + */ + public function getRunningLRTs() + { + // Return the result of the query + return $this->_ci->JobsQueueModel->execReadOnlyQuery(' + SELECT jq.* + FROM system.tbl_jobsqueue jq + WHERE jq.type IN ? + AND jq.status = ? + ORDER BY jq.creationtime DESC', + array( + $this->_ci->config->item(self::CFG_LRT_TYPES), + JobsQueueLib::STATUS_RUNNING + ) + ); + } + /** * Execute a LRT in background * - Checks if the wanted LRT exists in the applcation/controllers/lrts directory @@ -90,7 +110,12 @@ class LongRunTaskLib extends JobsQueueLib // Execute the LRT implementation (a CI controller from CLI) providing as parameter the jobid exec( // Command - '/usr/bin/php '.APPPATH.'../index.ci.php lrts/'.$lrt->{self::PROPERTY_TYPE}.'/run '.$lrt->{self::PROPERTY_JOBID}.' > /dev/null 2>&1 & echo $!', + sprintf( + '/usr/bin/php %s/../index.ci.php lrts/%s/run %s > /dev/null 2>&1 & echo $!', + APPPATH, + $lrt->{self::PROPERTY_TYPE}, + $lrt->{self::PROPERTY_JOBID} + ), $output // Here goes the output from the standard output and error ); @@ -110,17 +135,78 @@ class LongRunTaskLib extends JobsQueueLib } /** - * Set the LRT in the queue as failed + * Kill the provided LRT + * To avoid to kill a process that is not this LRT, + * since the same PID can be assigned to another process once this ended */ - public function lrtExecFailed($jobid) + public function killLrt($lrt) { - return $this->_ci->JobsQueueModel->update( - $jobid, + // Try to get the pid of this LRT from the system + $pid = exec( + sprintf( + 'ps -eo pid,cmd | grep "index.ci.php lrts/%s/run %s" | grep -v grep | awk \'{print $1}\'', + $lrt->{self::PROPERTY_TYPE}, + $lrt->{self::PROPERTY_JOBID} + ) + ); + + // If the pid is the same then kill the process with a SIGKILL + if ($pid == $lrt->{self::PROPERTY_PID}) exec('kill -9 '.$lrt->{self::PROPERTY_PID}.' > /dev/null 2>&1'); + + // Set the LRT as failed in any case + $lrtExecFailedResult = $this->_ci->JobsQueueModel->update( + $lrt->{self::PROPERTY_JOBID}, array( 'endtime' => 'NOW()', 'status' => self::STATUS_FAILED ) ); + // If an error occurred then return it + if (isError($lrtExecFailedResult)) return $lrtExecFailedResult; + } + + /** + * + */ + public function checkExecution($lrt) + { + // If the LRT stopped running + if (!$this->_isRunning($lrt)) + { + // Loads MessageLib library + $this->_ci->load->library('MessageLib'); + // Load the BenutzerModel + $this->_ci->load->model('person/Benutzer_model', 'BenutzerModel'); + + // Get the benutzer for this uid + $benutzerResult = $this->_ci->BenutzerModel->loadWhere(array('uid' => $lrt->{LongRunTaskLib::PROPERTY_UID})); + // If an error occurred then return it + if (isError($benutzerResult)) return $benutzerResult; + // If no benutzer has been found + if (!hasData($benutzerResult)) return error('No benutzer found, uid: '.$lrt->{LongRunTaskLib::PROPERTY_UID}); + + $benutzer = getData($benutzerResult)[0]; + + // Sends a message to the user + $messageResult = $this->_ci->messagelib->sendMessageUser( + $benutzer->person_id, + 'Long run task ended', + 'The long run task '.$lrt->{self::PROPERTY_TYPE}.' ended, output: '.$lrt->{self::PROPERTY_OUTPUT} + ); + // If an error occurred then return it + if (isError($messageResult)) return $messageResult; + + // Set the LRT as done + $lrtExecOverResult = $this->_ci->JobsQueueModel->update( + $lrt->{self::PROPERTY_JOBID}, + array( + 'endtime' => 'NOW()', + 'status' => self::STATUS_DONE + ) + ); + // If an error occurred then return it + if (isError($lrtExecOverResult)) return $lrtExecOverResult; + } } //------------------------------------------------------------------------------------------------------------------ @@ -222,18 +308,25 @@ class LongRunTaskLib extends JobsQueueLib return $this->_ci->JobsQueueModel->update($jobid, array('output' => json_encode($output))); } + //------------------------------------------------------------------------------------------------------------------ + // Private methods + /** - * Set the LRT in the queue as successfully ended + * Return true if the LRT is still running */ - public function lrtExecOver($jobid) + private function _isRunning($lrt) { - return $this->_ci->JobsQueueModel->update( - $jobid, - array( - 'endtime' => 'NOW()', - 'status' => self::STATUS_DONE + // Try to get the pid of this LRT from the system + $pid = exec( + sprintf( + 'ps -eo pid,cmd | grep "index.ci.php lrts/%s/run %s" | grep -v grep | awk \'{print $1}\'', + $lrt->{self::PROPERTY_TYPE}, + $lrt->{self::PROPERTY_JOBID} ) ); + + // If the pid is the same then the LRT is still running + return $pid == $lrt->{self::PROPERTY_PID}; } }