|
@@ -17,9 +17,147 @@
|
|
|
// - `output_type`: output mime type or namespace
|
|
// - `output_type`: output mime type or namespace
|
|
|
// - `progress`: if process implement progress. @param --progress_file=progress
|
|
// - `progress`: if process implement progress. @param --progress_file=progress
|
|
|
|
|
|
|
|
|
|
+Lib::loadClass('Request');
|
|
|
|
|
+Lib::loadClass('Core_AsyncJobsFiles');
|
|
|
|
|
+Lib::loadClass('Core_AsyncJobsDB');
|
|
|
|
|
+Lib::loadClass('Core_AsyncJobsServer'); // pm2
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * @usage: Core_AsyncJobs::startAsyncJob($idJob)
|
|
|
|
|
+ * -> Core_AsyncJobsServer::startAsyncJob(execPath, name, [ 'out.log', 'error.log', 'cwd', 'args' ])
|
|
|
|
|
+ */
|
|
|
|
|
+
|
|
|
class Core_AsyncJobs {
|
|
class Core_AsyncJobs {
|
|
|
- static $VERSION = 1; // `CRM_CONFIG`.`CONF_KEY` = 'Core_AsyncJobs__version'
|
|
|
|
|
- static $CRM_CONFIG_VERSION_KEY = 'Core_AsyncJobs__version';
|
|
|
|
|
|
|
+
|
|
|
|
|
+ static function registerNewAntTask($props) {
|
|
|
|
|
+ $namespace = V::get('namespace', '', $props);
|
|
|
|
|
+ $primaryKey = V::get('primaryKey', '', $props);
|
|
|
|
|
+ $ant_path = V::get('ant_path', '', $props);
|
|
|
|
|
+ $ant_template = V::get('ant_template', '', $props);
|
|
|
|
|
+
|
|
|
|
|
+ if (empty($namespace)) throw new Exception("Missing namespace");
|
|
|
|
|
+ if (empty($primaryKey)) throw new Exception("Missing primaryKey");
|
|
|
|
|
+ if (empty($ant_path)) throw new Exception("Missing ant_path");
|
|
|
|
|
+ if (empty($ant_template)) throw new Exception("Missing ant_template");
|
|
|
|
|
+
|
|
|
|
|
+ // https://biuro.biall-net.pl/dev-pl/se-master/index.php?_route=UrlAction_Ant
|
|
|
|
|
+ // & _task=ant
|
|
|
|
|
+ // & path=default_db.in7_dziennik_koresp/test-async
|
|
|
|
|
+ // & template=test-loop
|
|
|
|
|
+ // & typeName=default_db:IN7_DZIENNIK_KORESP
|
|
|
|
|
+ // & primaryKey=66263
|
|
|
|
|
+ // & primaryKeyField=ID
|
|
|
|
|
+
|
|
|
|
|
+ Lib::loadClass('ACL');
|
|
|
|
|
+ $acl = ACL::getAclByNamespace($namespace);
|
|
|
|
|
+ $typeName = Api_WfsNs::typeName($namespace);
|
|
|
|
|
+ $pkField = $acl->getPrimaryKeyField();
|
|
|
|
|
+
|
|
|
|
|
+ // DB::getPDO()->tryHandleException
|
|
|
|
|
+ $idJob = V::tryHandleException($handler = [ 'Core_AsyncJobs', 'isInstalled' ], $callback = [ 'Core_AsyncJobsDB', 'insert' ], $args = [
|
|
|
|
|
+ [
|
|
|
|
|
+ 'JOB_NAME' => "Ant|{$namespace}|{$ant_path}|{$ant_template}",
|
|
|
|
|
+ 'LOCK_VALUE' => $primaryKey,
|
|
|
|
|
+ 'USER' => User::getLogin(),
|
|
|
|
|
+ ],
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ {
|
|
|
|
|
+ $path = $ant_path; // default_db.in7_dziennik_koresp/test-async
|
|
|
|
|
+ $template = $ant_template; // test-loop
|
|
|
|
|
+
|
|
|
|
|
+ $webRootUrl = Request::getPathUri() . "schema/ant-url_action/{$path}"; // TODO: security - only for test
|
|
|
|
|
+ $outputFunctionUrl = Router::getRoute('UrlAction_Ant')->getLink('output') . "&path={$path}&file=";
|
|
|
|
|
+ $antFunctionUrl = Router::getRoute('UrlAction_Ant')->getLink('ant') . "&path={$path}&file={$file}&template={$template}&typeName={$typeName}&primaryKey={$primaryKey}&primaryKeyField={$pkField}"; // &confirmAntfile={$confirmAntfile}&confirmAntfileTarget={$confirmAntfileTarget} sdo confirmacji potrzebne - wzglednie przetwarzac z tresci output URL_TASK - ale potrzebne parametry analogiczne aby chodzily
|
|
|
|
|
+ // $testUrl = Request::getPathUri() . "wfs-data.php/default_db/?SERVICE=WFS&VERSION=1.0.0&TYPENAME={$typeName}&SRSNAME=EPSG:3003&featureID={$objectName}.{$primaryKey}";// &REQUEST=GetFeature
|
|
|
|
|
+ $uuid = date("Y-m-d-H_i_s") . substr(md5(time()), 0, 6); // TODO: uniq id for every request
|
|
|
|
|
+ Lib::loadClass('Crypt');
|
|
|
|
|
+ $passwordBase64Basic = base64_encode(User::getLogin() . ":" . Crypt::decrypt($_SESSION['ADM_PASS_HASH']));
|
|
|
|
|
+ // /* TODO: ??? */ if( strlen($confirmAntfile) > 0 ) $cmd .= " -DconfirmAntfile={$confirmAntfile}";
|
|
|
|
|
+ // /* TODO: ??? */ if( strlen($confirmAntfileTarget) > 0 ) $cmd .= " -DconfirmAntfileTarget={$confirmAntfileTarget}";
|
|
|
|
|
+ $php_session_id = session_id();
|
|
|
|
|
+ }
|
|
|
|
|
+ Core_AsyncJobsFiles::createNewJobFiles($idJob, $jobProps = [
|
|
|
|
|
+ 'webRootUrl' => $webRootUrl,
|
|
|
|
|
+ 'outputFunctionUrl' => $outputFunctionUrl,
|
|
|
|
|
+ 'antFunctionUrl' => $antFunctionUrl,
|
|
|
|
|
+ 'uuid' => $uuid,
|
|
|
|
|
+ 'passwordBase64Basic' => $passwordBase64Basic,
|
|
|
|
|
+ 'php_session_id' => $passwordBase64Basic,
|
|
|
|
|
+ 'xpath' => $pkField,
|
|
|
|
|
+ 'xpath_value' => $primaryKey,
|
|
|
|
|
+ 'template' => $template,
|
|
|
|
|
+ 'api_url' => Request::getPathUri()."wfs-data.php", //potrzebuje ten parametr do dzialania w AMS itp
|
|
|
|
|
+ 'typeName' => $typeName,
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ $jobStartScript = "";
|
|
|
|
|
+ {
|
|
|
|
|
+ $propFilePath = Core_AsyncJobsFiles::propertyFile($idJob, $today = date("Y-m-d"));
|
|
|
|
|
+ $cmd = "cd " . APP_PATH_SCHEMA . "/ant-url_action/{$ant_path}";
|
|
|
|
|
+ $cmd .= " && ";
|
|
|
|
|
+ $cmd .= implode(" ", [
|
|
|
|
|
+ 'ant',
|
|
|
|
|
+ '-S',
|
|
|
|
|
+ '-propertyfile', $propFilePath,
|
|
|
|
|
+ ($ant_template) ? $ant_template : '',
|
|
|
|
|
+ '2>&1',
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ $pathCmd = [];
|
|
|
|
|
+ $pathCmd[] = '/opt/local/bin/ant';
|
|
|
|
|
+ $pathCmd[] = '/bin';
|
|
|
|
|
+ $pathCmd[] = '/usr/bin';
|
|
|
|
|
+ $pathCmd[] = '/usr/local/bin';
|
|
|
|
|
+ $pathCmd[] = '/opt/local/bin';
|
|
|
|
|
+ $pathCmd[] = '/sbin';
|
|
|
|
|
+ $pathCmd[] = '/usr/sbin';
|
|
|
|
|
+ $pathCmd[] = '/opt/local/sbin/skrypty';
|
|
|
|
|
+ $pathCmd[] = '/opt/local/var/macports/software';
|
|
|
|
|
+ $pathCmd[] = '/Applications/Server.app/Contents/ServerRoot/usr/bin';
|
|
|
|
|
+ $pathCmd[] = '/Applications/Server.app/Contents/ServerRoot/usr/sbin';
|
|
|
|
|
+ $jobStartScript = implode("\n", [
|
|
|
|
|
+ 'export PATH=' . implode(':', $pathCmd),
|
|
|
|
|
+ 'JAVA_HOME="/usr/bin/java"',
|
|
|
|
|
+ 'MAVEN_OPTS="-Xms256m -Xmx512m"',
|
|
|
|
|
+ $cmd,
|
|
|
|
|
+ "",
|
|
|
|
|
+ ]);
|
|
|
|
|
+ }
|
|
|
|
|
+ Core_AsyncJobsFiles::createTaskStartScript($idJob, $jobDate = date("Y-m-d"), $jobStartScript);
|
|
|
|
|
+
|
|
|
|
|
+ return $idJob;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ static function startAsyncJob($idJob, $item = []) {
|
|
|
|
|
+ if (empty($item)) $item = Core_AsyncJobsDB::fetch($idJob);
|
|
|
|
|
+ DBG::nicePrint($item, '$item');
|
|
|
|
|
+ // Core_AsyncJobsFiles::basePath($idJob, $jobDate = $item['DATE']);
|
|
|
|
|
+ // Core_AsyncJobsFiles::propertyFile($idJob, $jobDate = $item['DATE']);
|
|
|
|
|
+ // Core_AsyncJobsFiles::startScript($idJob, $jobDate = $item['DATE']);
|
|
|
|
|
+ // Core_AsyncJobsFiles::outLog($idJob, $jobDate = $item['DATE']);
|
|
|
|
|
+ // Core_AsyncJobsFiles::errorLog($idJob, $jobDate = $item['DATE']);
|
|
|
|
|
+ $jobDate = $item['DATE'];
|
|
|
|
|
+ $execPath = Core_AsyncJobsFiles::startScript($idJob, $jobDate);
|
|
|
|
|
+
|
|
|
|
|
+ // Core_AsyncJobsServer::startAsyncJob(execPath, name, [ 'out.log', 'error.log', 'cwd', 'args' ])
|
|
|
|
|
+ $out = [];
|
|
|
|
|
+ $ret = Core_AsyncJobsServer::startAsyncJob(
|
|
|
|
|
+ $execPath,
|
|
|
|
|
+ $name = implode("|", [ $item['JOB_NAME'], $item['LOCK_VALUE'] ]),
|
|
|
|
|
+ [
|
|
|
|
|
+ 'out.log' => Core_AsyncJobsFiles::outLog($idJob, $jobDate),
|
|
|
|
|
+ 'error.log' => Core_AsyncJobsFiles::errorLog($idJob, $jobDate),
|
|
|
|
|
+ 'cwd' => dirname(Core_AsyncJobsFiles::basePath($idJob, $jobDate)),
|
|
|
|
|
+ ],
|
|
|
|
|
+ $out
|
|
|
|
|
+ );
|
|
|
|
|
+ if (0 === $ret) {
|
|
|
|
|
+ throw new AlertInfoException("Uruchomiono zadanie. " . implode(" ", $out));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ throw new Exception("Nie uruchomiono zadania. " . implode(" ", $out));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
static function getSimpleList() {
|
|
static function getSimpleList() {
|
|
|
$fullList = self::getFullList();
|
|
$fullList = self::getFullList();
|
|
@@ -72,41 +210,6 @@ class Core_AsyncJobs {
|
|
|
return V::shell_exec($cmd);
|
|
return V::shell_exec($cmd);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- static function startNewJob($jobName) {
|
|
|
|
|
- // for Ant:
|
|
|
|
|
- // index.php?_route=UrlAction_Ant&_task=ant&path=default_db.in7_dziennik_koresp/etykieta&typeName=default_db:IN7_DZIENNIK_KORESP&primaryKey=66263&primaryKeyField=ID
|
|
|
|
|
- // index.php?_route=UrlAction_Ant
|
|
|
|
|
- // & _task=ant
|
|
|
|
|
- // & path=default_db.in7_dziennik_koresp/test-bash
|
|
|
|
|
- // & typeName=default_db:IN7_DZIENNIK_KORESP
|
|
|
|
|
- // & primaryKey=66263
|
|
|
|
|
- // & primaryKeyField=ID
|
|
|
|
|
- // index.php?_route=UrlAction_Ant
|
|
|
|
|
- // & _task=ant
|
|
|
|
|
- // & path=default_db.in7_dziennik_koresp/test-bash
|
|
|
|
|
- // & template=test-loop
|
|
|
|
|
- // & typeName=default_db:IN7_DZIENNIK_KORESP
|
|
|
|
|
- // & primaryKey=66263
|
|
|
|
|
- // & primaryKeyField=ID
|
|
|
|
|
- // ant=default_db:IN7_DZIENNIK_KORESP/test-bash & task=test-loop & ns=default_db:IN7_DZIENNIK_KORESP & pk=66263
|
|
|
|
|
- if (empty($jobName)) throw new Exception("Missing job name");
|
|
|
|
|
- // $jobName - check if already started? pm2 will return failed
|
|
|
|
|
- $outLogPath = "p5-async-jobs/jobX/logs/out.log";
|
|
|
|
|
- $errorLogPath = "p5-async-jobs/jobX/logs/error.log";
|
|
|
|
|
- $jobExecPath = ""; // TODO: path to exec
|
|
|
|
|
- $args = ""; // args for script
|
|
|
|
|
- $cmd = implode(" ", [
|
|
|
|
|
- "pm2 start '{$jobExecPath}'",
|
|
|
|
|
- "--name '{$jobName}'",
|
|
|
|
|
- "--no-autorestart",
|
|
|
|
|
- "--output '{$outLogPath}'",
|
|
|
|
|
- "--error '{$errorLogPath}'",
|
|
|
|
|
- "--time", // prefix time to log entry
|
|
|
|
|
- "-- {$args}",
|
|
|
|
|
- ]);
|
|
|
|
|
- return V::shell_exec($cmd);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
static function deleteStopped() {
|
|
static function deleteStopped() {
|
|
|
// TODO: script to remove stopped in loop with delay
|
|
// TODO: script to remove stopped in loop with delay
|
|
|
// pm2 start app.js --restart-delay=3000
|
|
// pm2 start app.js --restart-delay=3000
|
|
@@ -131,178 +234,16 @@ class Core_AsyncJobs {
|
|
|
]);
|
|
]);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- static function getNodePath() { return "/usr/local/bin/node"; }
|
|
|
|
|
- // npm_path="/usr/local/bin/npm"
|
|
|
|
|
- static function getPm2Path() { return "/usr/local/bin/pm2"; }
|
|
|
|
|
- static function getPm2WwwUserPath() { return "/Library/WebServer/.pm2/"; }
|
|
|
|
|
static function isInstalled() {
|
|
static function isInstalled() {
|
|
|
- $confAsyncPath = Config::get('APP_PATH_ASYNC_JOB');
|
|
|
|
|
- if (!$confAsyncPath) throw new Exception("Missing Config APP_PATH_ASYNC_JOB");
|
|
|
|
|
|
|
+ if (!Core_AsyncJobsFiles::isInstalled()) throw new Exception("AsyncJobs files not installed");
|
|
|
|
|
|
|
|
- if (!file_exists($confAsyncPath)) {
|
|
|
|
|
- mkdir($confAsyncPath, $mode = 0777, $recursive = TRUE);
|
|
|
|
|
- }
|
|
|
|
|
- if (!file_exists($confAsyncPath)) throw new Exception("Folder not exists APP_PATH_ASYNC_JOB");
|
|
|
|
|
-
|
|
|
|
|
- // V::exec("/usr/local/bin/pm2 --version 2>&1", $out, $ret);
|
|
|
|
|
- V::exec("/usr/local/bin/pm2 ping 2>&1", $out, $ret); // expected "{ msg: 'pong' }"
|
|
|
|
|
- // echo UI::h('pre', [], "ret({$ret}):\n" . implode("\n", $out));
|
|
|
|
|
- if ($ret === 0) {
|
|
|
|
|
- // [PM2] Spawning PM2 daemon with pm2_home=/Library/WebServer/.pm2
|
|
|
|
|
- // [PM2] PM2 Successfully daemonized
|
|
|
|
|
- // { msg: 'pong' }
|
|
|
|
|
- }
|
|
|
|
|
- if ($ret !== 0) {
|
|
|
|
|
- if (!file_exists(self::getNodePath())) throw new Exception("pm2 not installed");
|
|
|
|
|
- // if [ ! -f "$node_path" ]; then
|
|
|
|
|
- // echo "$node_path not exists"
|
|
|
|
|
- // wget https://nodejs.org/dist/v12.15.0/node-v12.15.0.pkg
|
|
|
|
|
- // sudo installer -verbose -pkg node-v12.15.0.pkg -target /
|
|
|
|
|
- // fi
|
|
|
|
|
- // # node -v # expected v12.15.0
|
|
|
|
|
- if (!file_exists(self::getPm2Path())) throw new Exception("pm2 not installed");
|
|
|
|
|
- // npm install -g pm2
|
|
|
|
|
- // sudo npm install -g pm2
|
|
|
|
|
- // pm2 -version # expected 4.2.3
|
|
|
|
|
- if (!file_exists(self::getPm2WwwUserPath())) throw new Exception("pm2 user folder not exists");
|
|
|
|
|
- // FIX for Mac OS:
|
|
|
|
|
- // $ sudo mkdir /Library/WebServer/.pm2/
|
|
|
|
|
- // $ sudo chown _www /Library/WebServer/.pm2/
|
|
|
|
|
- throw new Exception("Error pm2"); // unknown error
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (!Core_AsyncJobsServer::isInstalled()) throw new Exception("AsyncJobs server not installed");
|
|
|
|
|
|
|
|
- if (!self::checkAsyncJobDatabase()) throw new Exception("Error database schema for AsyncJobs");
|
|
|
|
|
|
|
+ if (!Core_AsyncJobsDB::checkAsyncJobDatabase()) throw new Exception("AsyncJobs database schema not installed");
|
|
|
|
|
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- static function checkAsyncJobDatabase() {
|
|
|
|
|
- // `CRM_CONFIG`.`CONF_KEY` = 'Core_AsyncJobs__version'
|
|
|
|
|
- $dbVersion = (int)DB::getPDO()->fetchValue(" select CONV_VAL from CRM_CONFIG where CONF_KEY = :key ", [ ':key' => self::$CRM_CONFIG_VERSION_KEY ]);
|
|
|
|
|
- if ($dbVersion < 1) self::upgradeAsyncJobDatabaseToVersion1();
|
|
|
|
|
-
|
|
|
|
|
- // $dbVersion = (int)DB::getPDO()->fetchValue(" select CONV_VAL from CRM_CONFIG where CONF_KEY = :key ", [ ':key' => 'Core_AsyncJobs__version' ]);
|
|
|
|
|
- // if ($dbVersion < 2) self::upgradeAsyncJobDatabaseToVersion2();
|
|
|
|
|
-
|
|
|
|
|
- $dbVersion = (int)DB::getPDO()->fetchValue(" select CONV_VAL from CRM_CONFIG where CONF_KEY = :key ", [ ':key' => self::$CRM_CONFIG_VERSION_KEY ]);
|
|
|
|
|
-
|
|
|
|
|
- return ($dbVersion < self::$VERSION) ? false : true;
|
|
|
|
|
- }
|
|
|
|
|
- static function upgradeAsyncJobDatabaseToVersion1() {
|
|
|
|
|
-
|
|
|
|
|
- // - insertOrUpdate new row in `CRM_ASYNC_FUNCTIONS` ( $TODAY, $version, $user, $jobName )
|
|
|
|
|
- // - $JOB_ID = fetchValue select ID from `CRM_ASYNC_FUNCTIONS` where JOB_NAME = $jobName
|
|
|
|
|
- // - `CRM_ASYNC_FUNCTIONS`.`A_STATUS` default 'WAITING' - not started
|
|
|
|
|
- // - `CRM_ASYNC_FUNCTIONS`.`A_STATUS`: 'NORMAL' - started
|
|
|
|
|
- // - `CRM_ASYNC_FUNCTIONS`.`A_STATUS`: 'OFF_HARD' - not running
|
|
|
|
|
- // - `CRM_ASYNC_FUNCTIONS`.`A_STATUS`: 'DELETED' - removed
|
|
|
|
|
- $sql = "
|
|
|
|
|
- CREATE TABLE IF NOT EXISTS `CRM_ASYNC_FUNCTIONS` ( -- list of async function definitions / config
|
|
|
|
|
- `ID` int(11) NOT NULL AUTO_INCREMENT,
|
|
|
|
|
- `ID_ZASOB` int(11) NOT NULL DEFAULT 0, -- TODO - register function in CRM_LISTA_ZASOBOW URL_ACTION to set perms
|
|
|
|
|
- `JOB_NAME` varchar(200) NOT NULL,
|
|
|
|
|
- `VERSION` int(11) NOT NULL DEFAULT 0,
|
|
|
|
|
- `LOCK_TYPE` enum('ROW', 'TABLE', 'SYSTEM', 'NO_LOCK') DEFAULT 'ROW',
|
|
|
|
|
- -- ROW - only one active job per row, eg. create pdf, close FV, @require primaryKey in JOB.LOCK_VALUE
|
|
|
|
|
- -- TABLE - ony one active job per table, eg. update columns, make report, sync
|
|
|
|
|
- -- SYSTEM - only one active job
|
|
|
|
|
- -- TODO USER_... - lock per user
|
|
|
|
|
- -- NO_LOCK - allow multiple jobs
|
|
|
|
|
-
|
|
|
|
|
- -- `USER` varchar(20) NOT NULL,
|
|
|
|
|
- -- `DATE` date NOT NULL,
|
|
|
|
|
- -- `A_STATUS` enum('WAITING','NORMAL','WARNING','OFF_SOFT','OFF_HARD','DELETED') DEFAULT 'WAITING',
|
|
|
|
|
-
|
|
|
|
|
- `A_RECORD_CREATE_DATE` datetime NOT NULL,
|
|
|
|
|
- `A_RECORD_CREATE_AUTHOR` varchar(20) NOT NULL,
|
|
|
|
|
- `A_RECORD_UPDATE_DATE` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
|
|
|
|
- `A_RECORD_UPDATE_AUTHOR` varchar(20) NOT NULL,
|
|
|
|
|
- PRIMARY KEY (`ID`),
|
|
|
|
|
- UNIQUE KEY `JOB_NAME` (`JOB_NAME`),
|
|
|
|
|
- KEY `DATE` (`DATE`),
|
|
|
|
|
- KEY `A_STATUS` (`A_STATUS`),
|
|
|
|
|
- KEY `A_RECORD_UPDATE_DATE` (`A_RECORD_UPDATE_DATE`)
|
|
|
|
|
- ) ENGINE=MyISAM DEFAULT CHARSET=latin2;
|
|
|
|
|
- ";
|
|
|
|
|
- $sql = "
|
|
|
|
|
- CREATE TABLE IF NOT EXISTS `CRM_ASYNC_JOB_LOG` (
|
|
|
|
|
- `ID` int(11) NOT NULL AUTO_INCREMENT,
|
|
|
|
|
- `ID_FUNCTION` int(11) NOT NULL,
|
|
|
|
|
- `ID_SOURCE_JOB` int(11) NOT NULL DEFAULT 0, -- id job
|
|
|
|
|
- `P_ID` int(11) NOT NULL DEFAULT 0, -- parent job id
|
|
|
|
|
- `DATE` date NOT NULL,
|
|
|
|
|
- `VERSION` int(11) NOT NULL DEFAULT 0,
|
|
|
|
|
- `JOB_NAME` varchar(200) NOT NULL, -- copy from CRM_ASYNC_FUNCTIONS
|
|
|
|
|
- `LOCK_VALUE` varchar(200) NOT NULL DEFAULT '', -- second part for unique JOB_NAME eg. primaryKey
|
|
|
|
|
- `USER` varchar(20) NOT NULL, -- user who start this function
|
|
|
|
|
- `A_STATUS` enum('WAITING','NORMAL','WARNING','OFF_SOFT','OFF_HARD','DELETED') DEFAULT 'WAITING',
|
|
|
|
|
-
|
|
|
|
|
- `A_RECORD_CREATE_DATE` datetime NOT NULL,
|
|
|
|
|
- `A_RECORD_CREATE_AUTHOR` varchar(20) NOT NULL,
|
|
|
|
|
- `A_RECORD_UPDATE_DATE` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
|
|
|
|
- `A_RECORD_UPDATE_AUTHOR` varchar(20) NOT NULL,
|
|
|
|
|
- PRIMARY KEY (`ID`),
|
|
|
|
|
- UNIQUE KEY `JOB_LOCK` (`JOB_NAME`, `LOCK_VALUE`, `USER`), -- add USER to store user click and respond that job is running by other user
|
|
|
|
|
- KEY `DATE` (`DATE`),
|
|
|
|
|
- KEY `A_STATUS` (`A_STATUS`),
|
|
|
|
|
- KEY `A_RECORD_UPDATE_DATE` (`A_RECORD_UPDATE_DATE`)
|
|
|
|
|
- ) ENGINE=MyISAM DEFAULT CHARSET=latin2;
|
|
|
|
|
- ";
|
|
|
|
|
-
|
|
|
|
|
- // @usage:
|
|
|
|
|
- // `CRM_ASYNC_FUNCTIONS`.`JOB_NAME` = '
|
|
|
|
|
- // route = ant
|
|
|
|
|
- // -- & path = default_db.in7_dziennik_koresp/test-bash
|
|
|
|
|
- // & template = test-loop
|
|
|
|
|
- // & typeName = default_db:IN7_DZIENNIK_KORESP
|
|
|
|
|
- // & primaryKey = 66263
|
|
|
|
|
- // & primaryKeyField = ID
|
|
|
|
|
- // -> `CRM_ASYNC_FUNCTIONS`.`JOB_NAME` =
|
|
|
|
|
- // namespace = default_db/IN7_DZIENNIK_KORESP
|
|
|
|
|
- // ant = test-bash
|
|
|
|
|
- // template = test-loop
|
|
|
|
|
- // primaryKey = 66263
|
|
|
|
|
- // -> `CRM_ASYNC_FUNCTIONS`.`JOB_NAME` Format: "{$type}|..."
|
|
|
|
|
- // -> `CRM_ASYNC_FUNCTIONS`.`JOB_NAME` Format: "Ant|{$namespace}"
|
|
|
|
|
- // -> `CRM_ASYNC_JOB_LOG`.`LOCK_VALUE` Format: "{$primaryKey}|{$func_name}|..."
|
|
|
|
|
- // -> `CRM_ASYNC_JOB_LOG`.`LOCK_VALUE` Format: "{$primaryKey}|{$func_name}|{$template}"
|
|
|
|
|
- // -> Example: JOB_NAME = 'Ant|default_db/IN7_DZIENNIK_KORESP', LOCK_VALUE = '66263|test-bash|test-loop'
|
|
|
|
|
-
|
|
|
|
|
- // Add fields:
|
|
|
|
|
- // - function config at execution time:
|
|
|
|
|
- // - eg LOCK by user | feature | namespace | no_lock -- should contain in name
|
|
|
|
|
- // - process result - last result - NO - result from file, separate request needed
|
|
|
|
|
-
|
|
|
|
|
- // IDEA: 2 tables:
|
|
|
|
|
- // - `Config` - for function config (create row if not exists)
|
|
|
|
|
- // - `Log` - for log where JOB_ID is created or used from Config table
|
|
|
|
|
-
|
|
|
|
|
- // then createNewJob:
|
|
|
|
|
- // 1. fetch job config from CRM_ASYNC_FUNCTIONS_CONFIG
|
|
|
|
|
- // 1.1 IF 404 then create row, read config from function (how?)
|
|
|
|
|
- // 1.2 IF exists then check status and lock config
|
|
|
|
|
- // 1.2.1 IF online and lock then return error
|
|
|
|
|
- // 1.2.2 IF !online and !lock then create new row in Log table and return correct JOB_ID
|
|
|
|
|
-
|
|
|
|
|
- self::_upgdateAsyncJobDatabaseVersion($version = 1);
|
|
|
|
|
- }
|
|
|
|
|
- static function upgradeAsyncJobDatabaseToVersion2() {
|
|
|
|
|
- // ...
|
|
|
|
|
-
|
|
|
|
|
- self::_upgdateAsyncJobDatabaseVersion($version = 2);
|
|
|
|
|
- }
|
|
|
|
|
- static function _upgdateAsyncJobDatabaseVersion($version) {
|
|
|
|
|
- DB::getPDO()->insertOrUpdate('CRM_CONFIG', [
|
|
|
|
|
- 'CONF_KEY' => self::$CRM_CONFIG_VERSION_KEY,
|
|
|
|
|
- '@insert' => [
|
|
|
|
|
- 'CONF_VAL' => $version,
|
|
|
|
|
- ],
|
|
|
|
|
- '@update' => [
|
|
|
|
|
- 'CONF_VAL' => $version,
|
|
|
|
|
- ]
|
|
|
|
|
- ]);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
// pm2 logs -h
|
|
// pm2 logs -h
|
|
|
//
|
|
//
|
|
|
// Usage: logs [options] [id|name]
|
|
// Usage: logs [options] [id|name]
|