diff --git a/application/config/lrt.php b/application/config/lrt.php index 504f02d9a..64367a3da 100644 --- a/application/config/lrt.php +++ b/application/config/lrt.php @@ -16,5 +16,5 @@ $config['lrt_max_number_system'] = 100; $config['lrt_max_run_timeout'] = 48; // List of existing LRT types -$config['lrt_types'] = array('LRTDocumentConvertion'); +$config['lrt_types'] = array('LRTDummy'); diff --git a/application/controllers/jobs/LongRunTaskExecJob.php b/application/controllers/jobs/LongRunTaskExecJob.php new file mode 100644 index 000000000..f4bcfb5cf --- /dev/null +++ b/application/controllers/jobs/LongRunTaskExecJob.php @@ -0,0 +1,56 @@ +LogLibJob->setConfigs( + array( + 'dbExecuteUser' => get_class($this), + 'requestId' => 'LRT' + ) + ); + + // Loads LongRunTaskLib library + $this->load->library('LongRunTaskLib'); + } + + /** + * + */ + public function execEmAll() + { + $this->logInfo('Execute long run tasks started'); + + // Get all the LRTs that is possible to execute now + $lrtsResult = $this->longruntasklib->getLRTs(); + if (isError($lrtsResult)) return $lrtsResult; + + // For each LRT + foreach (getData($lrtsResult) as $lrt) + { + // Execute the task + $execResult = $this->longruntasklib->executeLrt($lrt); + // If an error occurred log it and continue with the next one + if (isError($execResult)) $this->logError(getError($execResult)); + } + + $this->logInfo('Execute long run tasks ended'); + } +} + diff --git a/application/controllers/lrts/LRTDummy.php b/application/controllers/lrts/LRTDummy.php new file mode 100644 index 000000000..88e4a383f --- /dev/null +++ b/application/controllers/lrts/LRTDummy.php @@ -0,0 +1,34 @@ +getLrt($jobid); + + // If an error occurred or a record has not been found + if (isError($lrtResult) || !hasData($lrtResult)) + { + $this->logError(getError($lrtResult)); + } + else + { + $lrt = getData($lrtResult)[0]; + $input = json_decode($lrt->input); + sleep((int)$input->sleep); + $this->setProgress($jobid, 100); + $this->setOutput($jobid, 'I slept for '.$input->sleep.' seconds'); + } + } +} + diff --git a/application/controllers/system/LRTTest.php b/application/controllers/system/LRTTest.php new file mode 100644 index 000000000..3db7c2c3b --- /dev/null +++ b/application/controllers/system/LRTTest.php @@ -0,0 +1,56 @@ + 'system/developer:r', + 'lrt1min' => 'system/developer:r', + ) + ); + + // Loads LongRunTaskLib library + $this->load->library('LongRunTaskLib'); + } + + // ----------------------------------------------------------------------------------------------------------------- + // Public methods + + /** + * Everything has a beginning + */ + public function index() + { + $this->load->view('system/lrtTest.php'); + } + + /** + * + */ + public function lrt1min() + { + $lrtInput = new stdClass(); + $lrtInput->sleep = 1; // Sleep for 1 min + + $this->outputJsonSuccess( + $this->longruntasklib->addNewLrtToQueue( + 'LRTDummy', // LRT type + getAuthUID(), // UID executer + $lrtInput // LRT input + ) + ); + } +} + diff --git a/application/core/LRT_Controller.php b/application/core/LRT_Controller.php index eb286a9d6..3b2aebe40 100644 --- a/application/core/LRT_Controller.php +++ b/application/core/LRT_Controller.php @@ -5,11 +5,13 @@ if (!defined("BASEPATH")) exit("No direct script access allowed"); /** * Long Run Task * - * This controller acts as interface of the LongRunTaskLib that contains + * - This controller acts as interface of the LongRunTaskLib that contains * all the needed functionalities to operate with the Long Run Task system * that is built on top of the Jobs Queue System - * This is an abstract class that provide basic functionalities, + * - This is an abstract class that provide basic functionalities, * it has to be extended to broaden its logic + * - Any implementation of a Long Run Task should extends this class to + * properly operate with the LRT system */ abstract class LRT_Controller extends JQW_Controller { @@ -23,8 +25,8 @@ abstract class LRT_Controller extends JQW_Controller // Changes the needed configs for LogLib $this->LogLibJob->setConfigs( array( - 'dbExecuteUser' => 'LRTs queue system', - 'requestId' => 'LTR' + 'dbExecuteUser' => get_class($this), + 'requestId' => 'LRT' ) ); @@ -32,42 +34,36 @@ abstract class LRT_Controller extends JQW_Controller $this->load->library('LongRunTaskLib'); } + //------------------------------------------------------------------------------------------------------------------ + // Public methods + + abstract public function run($jobid); + //------------------------------------------------------------------------------------------------------------------ // Protected methods - /** - * Get the oldest added LRTs to the queue having status = new - */ - protected function getLRTs() - { - $lrts = $this->longruntasklib->getLRTs(); - - // If an error occurred then log it in database - if (isError($lrts)) $this->logError(getError($lrts)); - - return $lrts; - } - /** * */ - protected function addNewLRTsToQueue($type, $lrts) + protected function getLrt($jobid) { - $result = $this->longruntasklib->addNewLRTsToQueue($type, $lrts); - - // If an error occurred then log it in database - if (isError($result)) $this->logError(getError($result), $type); - - return $result; + $this->longruntasklib->getLrt($jobid); } /** - * Utility method to generate a job with the given parameters and return it inside an array - * ready to be used by addNewJobsToQueue and updateJobsQueue + * */ - protected function generateJobs($status, $input) + protected function setProgress($jobid, $progress) { - return JobsQueueLib::generateJobs($status, $input); + $this->longruntasklib->setProgress($jobid, $progress); + } + + /** + * + */ + protected function setOutuput($jobid, $output) + { + $this->longruntasklib->setOutuput($jobid, $output); } } diff --git a/application/libraries/JobsQueueLib.php b/application/libraries/JobsQueueLib.php index 128a08994..cca22a9e1 100644 --- a/application/libraries/JobsQueueLib.php +++ b/application/libraries/JobsQueueLib.php @@ -255,8 +255,30 @@ class JobsQueueLib return array($job); } + //------------------------------------------------------------------------------------------------------------------ + // Protected methods + + /** + * Checks if the given job contains a valid type + */ + protected function _checkJobType($type, $types) + { + return $this->_inArray($type, $types, self::PROPERTY_TYPE); + } + //------------------------------------------------------------------------------------------------------------------ // Private methods + + /** + * Drop not allowed properties from the given job + */ + private function _dropNotAllowedPropertiesNewJob(&$job) + { + unset($job->{self::PROPERTY_JOBID}); + unset($job->{self::PROPERTY_CREATIONTIME}); + unset($job->{self::PROPERTY_TYPE}); + } + /** * Checks the job object structure when needed for insert @@ -283,34 +305,6 @@ class JobsQueueLib return false; // better sorry than wrong } - /** - * Checks the job object structure when needed for update - */ - private function _checkUpdateJobStructure(&$job) - { - // If job is a valid object - if (is_object($job) && property_exists($job, self::PROPERTY_JOBID)) return true; // it is valid! - - // If not object then object it! - if (!is_object($job)) $job = new stdClass(); - - // If an error property was not already previously stored then store an error message in job object - if (!property_exists($job, self::PROPERTY_ERROR)) - { - $job->{self::PROPERTY_ERROR} = 'The structure of the provided job is not valid'; - } - - return false; // better sorry than wrong - } - - /** - * Checks if the given job contains a valid type - */ - private function _checkJobType($type, $types) - { - return $this->_inArray($type, $types, self::PROPERTY_TYPE); - } - /** * Checks if the given job contains a valid status */ @@ -335,6 +329,26 @@ class JobsQueueLib return $found; } + /** + * Checks the job object structure when needed for update + */ + private function _checkUpdateJobStructure(&$job) + { + // If job is a valid object + if (is_object($job) && property_exists($job, self::PROPERTY_JOBID)) return true; // it is valid! + + // If not object then object it! + if (!is_object($job)) $job = new stdClass(); + + // If an error property was not already previously stored then store an error message in job object + if (!property_exists($job, self::PROPERTY_ERROR)) + { + $job->{self::PROPERTY_ERROR} = 'The structure of the provided job is not valid'; + } + + return false; // better sorry than wrong + } + /** * Search in an array the given value * The elements of the given array are objects @@ -356,16 +370,6 @@ class JobsQueueLib return $found; } - /** - * Drop not allowed properties from the given job - */ - private function _dropNotAllowedPropertiesNewJob(&$job) - { - unset($job->{self::PROPERTY_JOBID}); - unset($job->{self::PROPERTY_CREATIONTIME}); - unset($job->{self::PROPERTY_TYPE}); - } - /** * Drop not allowed properties from the given job */ diff --git a/application/libraries/LongRunTaskLib.php b/application/libraries/LongRunTaskLib.php index 4dded363b..78c020055 100644 --- a/application/libraries/LongRunTaskLib.php +++ b/application/libraries/LongRunTaskLib.php @@ -2,14 +2,20 @@ if (!defined('BASEPATH')) exit('No direct script access allowed'); +require_once 'JobsQueueLib.php'; + /** * Library that contains all the needed functionalities to operate with the Long Run Tasks */ class LongRunTaskLib extends JobsQueueLib { + // Config names const CFG_LRT_MAX_NUMBER_SYSTEM = 'lrt_max_number_system'; const CFG_LRT_TYPES = 'lrt_types'; + // LRT object properties + const PROPERTY_UID = 'uid'; + /** * Constructor */ @@ -22,7 +28,7 @@ class LongRunTaskLib extends JobsQueueLib } //------------------------------------------------------------------------------------------------------------------ - // Public methods + // Public methods used by the LongRunTaskExecJob /** * Get the oldest added LRTs to the queue having status = new @@ -32,35 +38,109 @@ class LongRunTaskLib extends JobsQueueLib public function getLRTs() { // Get all the running LRTs - $runningLrtsResult = $this->getJobsByTypeStatus($this->_ci->config->item(self::CFG_LRT_TYPES)), JobsQueueLib::STATUS_RUNNING); + $runningLrtsResult = $this->getJobsByTypeStatus($this->_ci->config->item(self::CFG_LRT_TYPES), JobsQueueLib::STATUS_RUNNING); if (isError($runningLrtsResult)) return $runningLrtsResult; // The number of the currently running LRTs - the maximum LRTs for the system - $max_number_of_lrts = $this->_ci->config->item(self::CFG_LRT_MAX_NUMBER_SYSTEM)) - count(getData($runningLrtsResult)); + $max_number_of_lrts = $this->_ci->config->item(self::CFG_LRT_MAX_NUMBER_SYSTEM) - count(getData($runningLrtsResult)); // Get the oldest LRTs added to the queue - return $this->getOldestJobs($this->_ci->config->item(self::CFG_LRT_TYPES)), $max_number_of_lrts); + return $this->getOldestJobs($this->_ci->config->item(self::CFG_LRT_TYPES), $max_number_of_lrts); } /** - * + * */ - public function addNewLRTsToQueue($type, $lrts) + public function executeLrt($lrt) { - return $this->addNewJobsToQueue($type, $lrts); + // If does _not_ exist a LRT implementation for this LRT type, then return an error + if ((include_once 'application/controllers/lrts/'.$lrt->{self::PROPERTY_TYPE}.'.php') !== true) + { + return error('The required LRT implementation has not been found'); + } + + // 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}.' &', + $output, // Here goes the output from the standard output and error + $return_var // Status of the command once executed (== 0 success, !=0 error) + ); } //------------------------------------------------------------------------------------------------------------------ - // Public static methods + // Public methods used by the front end applications (standard controllers/end points, ex. controllers/system/LRTTest.php) /** - * Utility method to generate a LTR with the given parameters and return it inside an array - * ready to be used by addNewLRTsToQueue + * Add a single LRT to the queue */ - public static function generateLtrs($status, $input) + public function addNewLrtToQueue($type, $uid, $lrtInput) { - return self::generateJobs($status, $input); + // Checks parameters + if (isEmptyString($type)) return error('The provided type parameter is not a valid string'); + if (isEmptyString($uid)) return error('The provided uid parameter is not a valid string'); + + // Convert input to JSON and check it + $jsonLrtInput = json_encode($lrtInput); + if ($jsonLrtInput == null) return error('The provided LRT input is not valid'); + + // Get all the job types + $dbResult = $this->_ci->JobTypesModel->load(); + if (isError($dbResult)) return $dbResult; + $types = getData($dbResult); + + // If the given type is not present in database + if (!$this->_checkJobType($type, $types)) return error('The provided type parameter is not valid'); + + // Get all the job statuses + $dbResult = $this->_ci->JobStatusesModel->load(); + if (isError($dbResult)) return $dbResult; + $statuses = getData($dbResult); + + // Create an object that represent the new tbl_jobsqueue record with the provided input + $lrt = $this->generateJobs(self::STATUS_NEW, $jsonLrtInput)[0]; + + // What you asked is what you get! + $lrt->{self::PROPERTY_TYPE} = $type; + $lrt->{self::PROPERTY_UID} = $uid; + + // Try to insert the single lrt into database + $dbNewLrtResult = $this->_ci->JobsQueueModel->insert($lrt); + + // If an error occurred during while inserting in database + if (isError($dbNewLrtResult)) return $dbNewLrtResult; + + return success('LRT added to the queue'); + } + + //------------------------------------------------------------------------------------------------------------------ + // Public methods used by the LRT implementation (controllers/ltrs/*, ex. controllers/ltrs/LRTDummy) + + /** + * Return a single record from the + */ + public function getLrt($jobid) + { + $this->_ci->JobsQueueModel->resetQuery(); + + return $this->_ci->JobsQueueModel->loadWhere(array('jobid' => $jobid)); + } + + /** + * + */ + public function setProgress($jobid, $progress) + { + return $this->_ci->JobsQueueModel->update($jobid, array('progress' => $progress)); + } + + /** + * + */ + public function setOutuput($jobid, $output) + { + return $this->_ci->JobsQueueModel->update($jobid, array('output' => json_encode($output))); } } diff --git a/application/views/system/lrtTest.php b/application/views/system/lrtTest.php new file mode 100644 index 000000000..44df1cad5 --- /dev/null +++ b/application/views/system/lrtTest.php @@ -0,0 +1,28 @@ + 'LRT Test Page', + 'axios027' => true, + 'bootstrap5' => true, + 'fontawesome6' => true, + 'vue3' => true, + 'navigationcomponent' => true, + 'phrases' => array( + 'global', + 'ui' + ), + 'customJSModules' => array('public/js/apps/LRTTest.js'), + ); + + $this->load->view('templates/FHC-Header', $includesArray); +?> + +
+ + + + +
+
+ +load->view('templates/FHC-Footer', $includesArray); ?> + diff --git a/public/js/api/LRTTEst.js b/public/js/api/LRTTEst.js new file mode 100644 index 000000000..11ba2c29a --- /dev/null +++ b/public/js/api/LRTTEst.js @@ -0,0 +1,9 @@ +export default { + addNew1MinLrt() + { + return { + method: 'post', + url: '/system/LRTTest/lrt1min' + }; + }, +} diff --git a/public/js/apps/LRTTest.js b/public/js/apps/LRTTest.js new file mode 100644 index 000000000..2d463731e --- /dev/null +++ b/public/js/apps/LRTTest.js @@ -0,0 +1,48 @@ +/** + * Copyright (C) 2022 fhcomplete.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import PluginsPhrasen from '../plugins/Phrasen.js'; +import {CoreNavigationCmpt} from '../components/navigation/Navigation.js' + +import ApiLrt from "../api/LRTTEst.js"; + +const lrtTestApp = Vue.createApp({ + data: function() { + return { + }; + }, + components: { + CoreNavigationCmpt, + }, + methods: { + addNew1MinLrt() { + this.$api.call(ApiLrt.addNew1MinLrt()) + .then(result => { + this.dropdowns.studiensemester_array = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + } + }, + template: ` + + ` +}); + +FhcApps.makeExtendable(lrtTestApp); + +lrtTestApp.use(PluginsPhrasen).mount('#main'); + diff --git a/system/dbupdate_3.4/76203_Asynchrone_Tasks.php b/system/dbupdate_3.4/76203_Asynchrone_Tasks.php index 67a358b87..2082dd9da 100644 --- a/system/dbupdate_3.4/76203_Asynchrone_Tasks.php +++ b/system/dbupdate_3.4/76203_Asynchrone_Tasks.php @@ -3,7 +3,7 @@ // Add column pid to system.tbl_jobsqueue if (!$result = @$db->db_query('SELECT "pid" FROM "system"."tbl_jobsqueue" LIMIT 1')) { - $qry = 'ALTER TABLE "system"."tbl_jobsqueue" ADD "pid" INT NULL DEFAULT 0;'; + $qry = 'ALTER TABLE "system"."tbl_jobsqueue" ADD "pid" INT NULL DEFAULT NULL;'; if (!$db->db_query($qry)) echo 'system.tbl_jobsqueue: '.$db->db_last_error().'
'; else