"lancer un script en tâche de fond", "usage" => "ApplicationClass args...", "sections" => [ parent::VERBOSITY_SECTION, ], ["-i", "--infos", "name" => "action", "value" => self::ACTION_INFOS, "help" => "Afficher des informations sur la tâche", ], ["-s", "--start", "name" => "action", "value" => self::ACTION_START, "help" => "Démarrer la tâche", ], ["-k", "--stop", "name" => "action", "value" => self::ACTION_STOP, "help" => "Arrêter la tâche", ], ]; protected int $action = self::ACTION_START; protected ?array $args = null; static function show_infos(RunFile $runfile, ?int $level=null): void { msg::print($runfile->getDesc(), $level); msg::print(yaml::with(["data" => $runfile->read()]), ($level ?? 0) - 1); } function main() { $args = $this->args; $appClass = $args[0] ?? null; if ($appClass === null) { self::die("Vous devez spécifier la classe de l'application"); } $appClass = $args[0] = str_replace("/", "\\", $appClass); if (!class_exists($appClass)) { self::die("$appClass: classe non trouvée"); } $useRunfile = constant("$appClass::USE_RUNFILE"); if (!$useRunfile) { self::die("Cette application ne supporte le lancement en tâche de fond"); } $runfile = app::with($appClass)->getRunfile(); switch ($this->action) { case self::ACTION_START: $argc = count($args); $appClass::_manage_runfile($argc, $args, $runfile); if ($runfile->warnIfLocked()) self::exit(app::EC_LOCKED); array_splice($args, 0, 0, [ PHP_BINARY, path::abspath(NULIB_APP_app_launcher), ]); app::params_putenv(); self::_start($args, $runfile); break; case self::ACTION_STOP: self::_stop($runfile); self::show_infos($runfile, -1); break; case self::ACTION_INFOS: self::show_infos($runfile); break; } } public static function _start(array $args, Runfile $runfile): void { $pid = pcntl_fork(); if ($pid == -1) { # parent, impossible de forker throw new ExitError(app::EC_FORK_PARENT, "Unable to fork"); } elseif (!$pid) { # child, fork ok $runfile->wfPrepare($pid); $outfile = $runfile->getOutfile() ?? "/tmp/NULIB_APP_app_console.out"; $exitcode = app::EC_FORK_CHILD; try { # rediriger STDIN, STDOUT et STDERR fclose(fopen($outfile, "wb")); // vider le fichier fclose(STDIN); $in = fopen("/dev/null", "rb"); fclose(STDOUT); $out = fopen($outfile, "ab"); fclose(STDERR); $err = fopen($outfile, "ab"); # puis lancer la commande $cmd = new Cmd($args); $cmd->addSource("/g/init.env"); $cmd->addRedir("both", $outfile, true); $cmd->fork_exec($exitcode, false); sh::_waitpid(-$pid, $exitcode); } finally { $runfile->wfReaped($exitcode); } } } public static function _stop(Runfile $runfile): bool { $data = $runfile->read(); $pid = $runfile->_getCid($data); msg::action("stop $pid"); if ($runfile->wfKill($reason)) { msg::asuccess(); return true; } else { msg::afailure($reason); return false; } } }