diff --git a/lib/classes/module/console/taskrun.class.php b/lib/classes/module/console/taskrun.class.php index 61a48391f1..cce41dafd1 100644 --- a/lib/classes/module/console/taskrun.class.php +++ b/lib/classes/module/console/taskrun.class.php @@ -59,7 +59,7 @@ class module_console_taskrun extends Command { if ($this->task) { $this->task->log(sprintf("signal %s received", $signo)); - if ($signo == SIGTERM) { + if ($signo == SIGTERM || $signo == SIGINT) { $this->task->setRunning(false); } } @@ -113,7 +113,6 @@ class module_console_taskrun extends Command $logfile = __DIR__ . '/../../../../logs/task_' . $task_id . '.log'; $handler = new Handler\RotatingFileHandler($logfile, 10); $logger->pushHandler($handler); - $this->task = $task_manager->getTask($task_id, $logger); register_tick_function(array($this, 'tick_handler'), true); @@ -121,6 +120,8 @@ class module_console_taskrun extends Command if (function_exists('pcntl_signal')) { pcntl_signal(SIGTERM, array($this, 'sig_handler')); + pcntl_signal(SIGINT, array($this, 'sig_handler')); + // pcntl_signal(SIGKILL, array($this, 'sig_handler')); } try { diff --git a/lib/classes/task/abstract.class.php b/lib/classes/task/abstract.class.php index 4e466bb726..de54f355a7 100755 --- a/lib/classes/task/abstract.class.php +++ b/lib/classes/task/abstract.class.php @@ -97,7 +97,8 @@ abstract class task_abstract protected $taskid = NULL; protected $system = ''; // "DARWIN", "WINDOWS" , "LINUX"... protected $argt = array( - "--help" => array("set" => false, "values" => array(), "usage" => " (no help available)") + "--help" => array( + 'set' => false, "values" => array(), "usage" => " (no help available)") ); /** @@ -107,51 +108,45 @@ abstract class task_abstract */ public function getState() { + static $stmt = NULL; $conn = connection::getPDOConnection(); - $sql = 'SELECT status FROM task2 WHERE task_id = :taskid'; - $stmt = $conn->prepare($sql); + if ( ! $stmt) { + $sql = 'SELECT status FROM task2 WHERE task_id = :taskid'; + $stmt = $conn->prepare($sql); + } $stmt->execute(array(':taskid' => $this->taskid)); $row = $stmt->fetch(PDO::FETCH_ASSOC); $stmt->closeCursor(); if ( ! $row) { throw new Exception('Unknown task id'); } - + unset($conn); return $row['status']; } /** - * to be overwritten by tasks : echo text to be included in
in task interface + * to be overwritten by tasks : ECHO text to be included in in task interface */ public function printInterfaceHEAD() { - return false; + } /** - * to be overwritten by tasks : echo javascript to be included in in task interface + * to be overwritten by tasks : ECHO javascript to be included in in task interface */ public function printInterfaceJS() { - return false; + } /** * * @return boolean */ - public function printInterfaceHTML() + public function hasInterfaceHTML() { - return false; - } - - /** - * - * @return boolean - */ - public function getGraphicForm() - { - return false; + return method_exists($this, "getInterfaceHTML"); } /** @@ -163,12 +158,12 @@ abstract class task_abstract public function setState($status) { $av_status = array( - self::STATE_STARTED - , self::STATE_TOSTOP - , self::STATE_STOPPED - , self::STATE_TORESTART - , self::STATE_TOSTART - , self::STATE_TODELETE + self::STATE_STARTED, + self::STATE_TOSTOP, + self::STATE_STOPPED, + self::STATE_TORESTART, + self::STATE_TOSTART, + self::STATE_TODELETE ); if ( ! in_array($status, $av_status)) { @@ -184,21 +179,30 @@ abstract class task_abstract $this->log(sprintf("task %d <- %s", $this->getID(), $status)); } - // 'active' means 'auto-start when scheduler starts' - public function setActive($boolean) + /** + * + * @param boolean $active 'active' means 'auto-start when scheduler starts' + * @return \task_abstract + */ + public function setActive($active) { $conn = connection::getPDOConnection(); $sql = 'UPDATE task2 SET active = :active WHERE task_id = :taskid'; $stmt = $conn->prepare($sql); - $stmt->execute(array(':active' => ($boolean ? '1' : '0'), ':taskid' => $this->getID())); + $stmt->execute(array(':active' => ($active ? '1' : '0'), ':taskid' => $this->getID())); $stmt->closeCursor(); - $this->active = ! ! $boolean; + $this->active = ! ! $active; return $this; } + /** + * + * @param string $title + * @return \task_abstract + */ public function setTitle($title) { $title = strip_tags($title); @@ -214,6 +218,12 @@ abstract class task_abstract return $this; } + /** + * + * @param string $settings xml settings as STRING + * @throws Exception_InvalidArgument if not proper xml + * @return \task_abstract + */ public function setSettings($settings) { if (@simplexml_load_string($settings) === FALSE) { @@ -230,8 +240,14 @@ abstract class task_abstract $this->settings = $settings; $this->loadSettings(simplexml_load_string($settings)); + + return $this; } + /** + * + * @return \task_abstract + */ public function resetCrashCounter() { $conn = connection::getPDOConnection(); @@ -246,11 +262,19 @@ abstract class task_abstract return $this; } + /** + * + * @return int + */ public function getCrashCounter() { return $this->crash_counter; } + /** + * + * @return int + */ public function incrementCrashCounter() { $conn = connection::getPDOConnection(); @@ -260,20 +284,32 @@ abstract class task_abstract $stmt->execute(array(':taskid' => $this->getID())); $stmt->closeCursor(); - return $this->crash_counter ++; + return ++ $this->crash_counter; } + /** + * + * @return string + */ public function getSettings() { return $this->settings; } - // 'active' means 'auto-start when scheduler starts' + /** + * + * @return boolean + * 'active' means 'auto-start when scheduler starts' + */ public function isActive() { return $this->active; } + /** + * + * @return int + */ public function getCompletedPercentage() { return $this->completed_percentage; @@ -319,15 +355,30 @@ abstract class task_abstract $this->active = ! ! $row['active']; $this->settings = $row['settings']; $this->runner = $row['runner']; - $this->completed_percentage = (integer) $row['completed']; - $this->loadSettings(simplexml_load_string($row['settings'])); + $this->completed_percentage = (int) $row['completed']; + $this->settings = $row['settings']; + + $sx = @simplexml_load_string($this->settings); + if ($sx) { + $this->loadSettings($sx); + } } + /** + * + * @return enum (self::RUNNER_MANUAL or self::RUNNER_SCHEDULER) + */ public function getRunner() { return $this->runner; } + /** + * + * @param enum $runner (self::RUNNER_MANUAL or self::RUNNER_SCHEDULER) + * @throws Exception_InvalidArgument + * @return \task_abstract + */ public function setRunner($runner) { if ($runner != self::RUNNER_MANUAL && $runner != self::RUNNER_SCHEDULER) { @@ -347,13 +398,22 @@ abstract class task_abstract $stmt = $conn->prepare($sql); $stmt->execute($params); $stmt->closeCursor(); + + return $this; } + /** + * + * @return string + */ public function getTitle() { return $this->title; } + /** + * + */ public function delete() { if ( ! $this->getPID()) { // do not delete a running task @@ -369,6 +429,9 @@ abstract class task_abstract } } + /** + * set last execution time to now() + */ public function setLastExecTime() { $conn = connection::getPDOConnection(); @@ -380,7 +443,7 @@ abstract class task_abstract /** * Return the last time the task was executed - * + * * @return null|\DateTime */ public function getLastExecTime() @@ -397,10 +460,16 @@ abstract class task_abstract if ($row['last_exec_time'] != '0000-00-00 00:00:00') { $time = new \DateTime($row['last_exec_time']); } - + return $time; } + /** + * + * @return variant + * pid (int) of the task, or NULL if the pid file + * NULL : the pid file is not locked (task no running) + */ public function getPID() { $pid = NULL; @@ -421,6 +490,11 @@ abstract class task_abstract return $pid; } + /** + * + * @param boolean $stat + * set to false to ask the task to quit its loop + */ public function setRunning($stat) { $this->running = $stat; @@ -445,6 +519,12 @@ abstract class task_abstract } } + /** + * sleep n seconds + * + * @param int $nsec + * @throws \InvalidArgumentException + */ protected function sleep($nsec) { $nsec = (integer) $nsec; @@ -455,16 +535,25 @@ abstract class task_abstract } } + /** + * + * @return string fullpath to the pid file for the task + */ private function getLockfilePath() { $core = \bootstrap::getCore(); $lockdir = $core->getRegistry()->get('GV_RootPath') . 'tmp/locks/'; - $lockfile = ($lockdir . 'task_' . $this->getID() . '.lock'); + $lockfilePath = ($lockdir . 'task_' . $this->getID() . '.lock'); - return($lockfile); + return($lockfilePath); } + /** + * + * @return resource file descriptor of the OPENED pid file + * @throws Exception if file is already locked (task running) + */ private function lockTask() { $lockfile = $this->getLockfilePath(); @@ -504,9 +593,12 @@ abstract class task_abstract try { $this->run2(); } catch (\Exception $exception) { - + } + if ($this->getState() === self::STATE_STARTED && $this->runner === self::RUNNER_MANUAL) + $this->setState(self::STATE_STOPPED); + // in any case, exception or not, the task is ending so unlock the pid file $this->unlockTask($lockFD); @@ -516,7 +608,11 @@ abstract class task_abstract } } - public function unlockTask($lockFD) + /** + * + * @param resource $lockFD file descriptor of the OPENED lock file + */ + private function unlockTask($lockFD) { flock($lockFD, LOCK_UN | LOCK_NB); ftruncate($lockFD, 0); @@ -563,9 +659,11 @@ abstract class task_abstract // post-process $this->postProcessOneContent($box, $row); + $rowsdone ++; + $current_memory = memory_get_usage(); if ($current_memory >> 20 >= $this->maxmegs) { - $this->log(sprintf("Max memory (%s M) reached (actual is %s M)", $this->maxmegs, $current_memory)); + $this->log(sprintf("Max memory (%s M) reached (actual is %.02f M)", $this->maxmegs, ($current_memory >> 10) / 1024)); $this->running = FALSE; $ret = self::STATE_MAXMEGSREACHED; } @@ -577,8 +675,7 @@ abstract class task_abstract } try { - $status = $this->getState(); - if ($status == self::STATE_TOSTOP) { + if ($this->getState() == self::STATE_TOSTOP) { $this->running = FALSE; $ret = self::STATE_TOSTOP; } @@ -592,11 +689,11 @@ abstract class task_abstract } // // if nothing was done, at least check the status - if (count($rs) == 0 && $this->running) { + if ($rowsdone == 0 && $this->running) { $current_memory = memory_get_usage(); if ($current_memory >> 20 >= $this->maxmegs) { - $this->log(sprintf("Max memory (%s M) reached (current is %s M)", $this->maxmegs, $current_memory)); + $this->log(sprintf("Max memory (%s M) reached (current is %.02f M)", $this->maxmegs, ($current_memory >> 10) / 1024)); $this->running = FALSE; $ret = self::STATE_MAXMEGSREACHED; } @@ -689,8 +786,8 @@ abstract class task_abstract /** * * @param appbox $appbox - * @param type $class_name - * @param type $settings + * @param string $class_name + * @param string $settings (xml string) * @return task_abstract */ public static function create(appbox $appbox, $class_name, $settings = null) @@ -741,11 +838,21 @@ abstract class task_abstract return($t); } + /** + * + * @return int id of the task + */ public function getID() { return $this->taskid; } + /** + * + * @param int $done + * @param int $todo + * @return \task_abstract + */ public function setProgress($done, $todo) { $p = ($todo > 0) ? ((100 * $done) / $todo) : -1; @@ -754,11 +861,14 @@ abstract class task_abstract $conn = connection::getPDOConnection(); $sql = 'UPDATE task2 SET completed = :p WHERE task_id = :taskid'; $stmt = $conn->prepare($sql); - $stmt->execute(array(':p' => $p, ':taskid' => $this->getID())); + $stmt->execute(array( + ':p' => $p, + ':taskid' => $this->getID() + )); $stmt->closeCursor(); $this->completed_percentage = $p; } catch (Exception $e) { - + } return $this; diff --git a/lib/classes/task/appboxAbstract.class.php b/lib/classes/task/appboxAbstract.class.php index fff2bb772b..b80d3fa771 100755 --- a/lib/classes/task/appboxAbstract.class.php +++ b/lib/classes/task/appboxAbstract.class.php @@ -84,6 +84,7 @@ abstract class task_appboxAbstract extends task_abstract switch ($process_ret) { case self::STATE_MAXMEGSREACHED: case self::STATE_MAXRECSDONE: + case self::STATE_OK: if ($this->getRunner() == self::RUNNER_SCHEDULER) { $this->setState(self::STATE_TORESTART); $this->running = FALSE; @@ -99,9 +100,6 @@ abstract class task_appboxAbstract extends task_abstract $this->setState(self::STATE_TODELETE); $this->running = FALSE; break; - - case self::STATE_OK: - break; } } // if(row) @@ -118,7 +116,7 @@ abstract class task_appboxAbstract extends task_abstract */ protected function process(appbox $appbox) { - $ret = self::STATE_OK; + $ret = self::STATE_OK; try { // get the records to process @@ -126,7 +124,6 @@ abstract class task_appboxAbstract extends task_abstract // process the records $ret = $this->processLoop($appbox, $rs); - } catch (Exception $e) { $this->log('Error : ' . $e->getMessage()); } diff --git a/lib/classes/task/databoxAbstract.class.php b/lib/classes/task/databoxAbstract.class.php index c735a599f3..01aee7f427 100755 --- a/lib/classes/task/databoxAbstract.class.php +++ b/lib/classes/task/databoxAbstract.class.php @@ -85,7 +85,7 @@ abstract class task_databoxAbstract extends task_abstract try { // get the records to process - $databox = databox::get_instance((int)$row['sbas_id']); + $databox = databox::get_instance((int) $row['sbas_id']); } catch (Exception $e) { $this->log(sprintf('Warning : can\' connect to sbas(%s)', $row['sbas_id'])); continue; @@ -111,6 +111,7 @@ abstract class task_databoxAbstract extends task_abstract switch ($process_ret) { case self::STATE_MAXMEGSREACHED: case self::STATE_MAXRECSDONE: + case self::STATE_OK: if ($this->getRunner() == self::RUNNER_SCHEDULER) { $this->setState(self::STATE_TORESTART); $this->running = FALSE; @@ -126,9 +127,6 @@ abstract class task_databoxAbstract extends task_abstract // DO NOT SUICIDE IN THE LOOP, may have to work on other sbas !!! $task_must_delete = TRUE; break; - - case self::STATE_OK: - break; } $this->flushRecordsSbas(); @@ -160,7 +158,6 @@ abstract class task_databoxAbstract extends task_abstract // process the records $ret = $this->processLoop($databox, $rs); - } catch (Exception $e) { $this->log('Error : ' . $e->getMessage()); } diff --git a/lib/classes/task/period/archive.class.php b/lib/classes/task/period/archive.class.php index 90a0861b7a..b3c41aaec2 100755 --- a/lib/classes/task/period/archive.class.php +++ b/lib/classes/task/period/archive.class.php @@ -212,20 +212,11 @@ class task_period_archive extends task_abstract } /** - * - * @return string - */ - public function getGraphicForm() - { - return true; - } - - /** - * printInterfaceHTML(..) : generer l'interface 'graphic view' + * getInterfaceHTML(..) : retourner l'interface 'graphic view' * * @return Void */ - public function printInterfaceHTML() + public function getInterfaceHTML() { $appbox = appbox::get_instance(\bootstrap::getCore()); @@ -264,9 +255,8 @@ class task_period_archive extends task_abstract