Core  3.2
PHP API documentation
 All Data Structures Namespaces Files Functions Variables Pages
Class.processExecuteAPI.php
Go to the documentation of this file.
1 <?php
2 class processExecuteAPIException extends \Exception
3 {
4 }
5 
7 {
8 }
9 
11 {
12  public static $debug = false;
13 
14  public static function run(Action & $action)
15  {
16  include_once ("FDL/Class.DocFam.php");
17  include_once ("FDL/Class.DocTimer.php");
18  include_once ("FDL/Class.SearchDoc.php");
19 
20  $usage = new ApiUsage();
21  $usage->setDefinitionText("Execute Dynacase Processes when needed");
22  $doctimerId = $usage->addOptionalParameter('doctimer-id', 'Doctimer identifier', null, null);
23  $execId = $usage->addOptionalParameter('exec-id', 'Exec identifier', null, null);
24  self::$debug = ($usage->addEmptyParameter('debug', 'Enable debugging verbose output') !== false);
25  $usage->verify();
26 
27  if ($doctimerId !== null && $execId !== null) {
28  throw new processExecuteAPIException("Error: only one of '--doctimer-id' or '--exec-id'' should be used.\n");
29  }
30 
31  if ($doctimerId !== null) {
32  self::execute_doctimer($action, $doctimerId);
33  } elseif ($execId !== null) {
34  self::execute_exec($action, $execId);
35  } else {
36  try {
37  self::execute_all($action);
38  }
40  /* Skip execution and silently ignore already running processes */
41  }
42  }
43  }
44 
45  protected static function lock(Action & $action)
46  {
47  self::debug(sprintf("Locking exclusive execution..."));
48  $i1 = unpack("i", "PROC") [1];
49  $i2 = unpack("i", "EXEC") [1];
50  simpleQuery($action->dbaccess, sprintf("SELECT pg_try_advisory_lock(%d, %d)", $i1, $i2) , $res, true, true, true);
51  if ($res !== 't') {
52  $msg = sprintf("A 'processExecute' API script is already running.");
53  self::debug($msg);
55  }
56  self::debug(sprintf("Exclusive execution locked."));
57  return $res;
58  }
59 
60  protected static function unlock(Action & $action, $lock)
61  {
62  /* Unlock will be performed when the process exits and the Postgres connection is torn down. */
63  }
64 
65  static function debug($msg)
66  {
67  if (self::$debug) {
68  error_log($msg);
69  }
70  }
71 
72  static function execute_all($action)
73  {
74  $lock = self::lock($action);
75  try {
76  self::verifyExecDocuments($action);
77  self::verifyTimerDocuments($action);
78  }
79  catch(\Exception $e) {
80  self::unlock($action, $lock);
81  throw $e;
82  }
83  self::unlock($action, $lock);
84  }
85 
86  static function execute_doctimer(Action & $action, $doctimerId)
87  {
88  $dt = new DocTimer($action->dbaccess, $doctimerId);
89  $time_start = microtime(true);
90  $err = $dt->executeTimerNow();
91  $time_end = microtime(true);
92  $time = $time_end - $time_start;
93  if ($err) {
94  $action->log->error(sprintf("Error while executing timer %s (%d): %s in %.03f seconds", $dt->title, $dt->id, $err, $time));
95  print sprintf("Error while executing timer %s (%d): %s in %.03f seconds", $dt->title, $dt->id, $err, $time);
96  } else {
97  $action->log->info(sprintf("Timer %s (%d) executed in %.03f seconds", $dt->title, $dt->id, $time));
98  print sprintf("Timer %s (%d) executed in %.03f seconds", $dt->title, $dt->id, $time);
99  }
100  }
101  /**
102  * @param Action $action
103  * @param \Dcp\Family\Exec|string $exec
104  */
105  static function execute_exec(Action & $action, $exec)
106  {
107  if (is_scalar($exec)) {
108  /**
109  * @var \Dcp\Family\Exec $exec
110  */
111  $exec = new_Doc($action->dbaccess, $exec, true);
112  }
113  if (!is_object($exec) || !is_a($exec, '\Dcp\Family\Exec') || !$exec->isAlive()) {
114  return;
115  }
116  $exec->executeNow();
117  }
118 
119  static function verifyExecDocuments(Action & $action)
120  {
121  // Verify EXEC document
122  $now = Doc::getTimeDate();
123 
124  $s = new SearchDoc($action->dbaccess, "EXEC");
125  $s->setObjectReturn();
126  $s->addFilter(sprintf("exec_nextdate < %s", pg_escape_literal($now)));
127  $s->addFilter("exec_status is null or exec_status = 'none'");
128  // $s->setDebugMode();
129  $s->search();
130 
131  while ($de = $s->getNextDoc()) {
132  $de->setValue("exec_status", "waiting");
133  $de->modify(true, array(
134  "exec_status"
135  ) , true);
136  }
137 
138  $s = new SearchDoc($action->dbaccess, "EXEC");
139  $s->setObjectReturn();
140  $s->addFilter(sprintf("exec_nextdate < %s", pg_escape_literal($now)));
141  $s->addFilter("exec_status != 'progressing'");
142  //$s->setDebugMode();
143  $s->search();
144  //print_r2($s->getDebugInfo());
145  self::debug(__METHOD__ . " " . sprintf("Found %d documents to execute.", $s->count()));
146  if ($s->count() <= 0) {
147  return;
148  }
149 
150  while ($de = $s->getNextDoc()) {
151  /**
152  * @var \Dcp\Core\ExecProcessus $de
153  */
154  self::debug(__METHOD__ . " " . sprintf("Executing document '%s' (%d).", $de->getTitle() , $de->id));
155  self::execute_exec($action, $de);
156  }
157  unset($exec);
158  return;
159  }
160 
161  static function verifyTimerDocuments(Action & $action)
162  {
163  // Verify EXEC document
164  $dt = new DocTimer($action->dbaccess);
165  $ate = $dt->getActionsToExecute();
166 
167  self::debug(__METHOD__ . " " . sprintf("Found %d doctimers.", count($ate)));
168  foreach ($ate as $k => $v) {
169  try {
170  $tmpfile = tempnam(getTmpDir() , __METHOD__);
171  if ($tmpfile === false) {
172  throw new \Exception("Error: could not create temporary file.");
173  }
174  $cmd = sprintf("%s/wsh.php --api=processExecute --doctimer-id=%s > %s 2>&1", DEFAULT_PUBDIR, escapeshellarg($v['id']) , escapeshellarg($tmpfile));
175  self::debug(__METHOD__ . " " . sprintf("Running '%s'", $cmd));
176  system($cmd, $ret);
177  $out = file_get_contents($tmpfile);
178  unlink($tmpfile);
179  if ($ret !== 0) {
180  throw new \Exception(sprintf("Process '%s' returned with error (%d): %s", $cmd, $ret, $out));
181  }
182  }
183  catch(\Exception $e) {
184  $errMsg = formatErrorLogException($e);
185 
186  error_log($errMsg);
187  if (!isInteractiveCLI()) {
188  $expand = array(
189  'm' => preg_replace('/^([^\n]*).*/s', '\1', $e->getMessage())
190  );
191  _wsh_send_error($errMsg, $expand);
192  }
193  }
194  }
195  }
196 }
$tmpfile
global $action
$dt
Definition: dav.php:69
static execute_doctimer(Action &$action, $doctimerId)
$ret
_wsh_send_error($errMsg, $expand=array())
Definition: Lib.Main.php:441
info($msg)
static verifyTimerDocuments(Action &$action)
if($famId) $s
isInteractiveCLI()
Definition: Lib.Main.php:430
const DEFAULT_PUBDIR
Definition: Lib.Prefix.php:28
static run(Action &$action)
foreach($argv as $arg) $cmd
error($msg)
static lock(Action &$action)
formatErrorLogException($e)
Definition: Lib.Main.php:548
print
Definition: checklist.php:49
getTmpDir($def= '/tmp')
Definition: Lib.Common.php:150
new_Doc($dbaccess, $id= '', $latest=false)
static unlock(Action &$action, $lock)
static getTimeDate($hourdelta=0, $second=false)
Definition: Class.Doc.php:8826
simpleQuery($dbaccess, $query, &$result=array(), $singlecolumn=false, $singleresult=false, $useStrict=null)
Definition: Lib.Common.php:484
if($file) if($subject==""&&$file) if($subject=="") $err
$usage
Verify arguments for wsh programs.
← centre documentaire © anakeen