Friendica Communications Platform (please note that this is a clone of the repository at github, issues are handled there) https://friendi.ca
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

692 rindas
20KB

  1. <?php
  2. use Friendica\Core\Config;
  3. if (!file_exists("boot.php") AND (sizeof($_SERVER["argv"]) != 0)) {
  4. $directory = dirname($_SERVER["argv"][0]);
  5. if (substr($directory, 0, 1) != "/")
  6. $directory = $_SERVER["PWD"]."/".$directory;
  7. $directory = realpath($directory."/..");
  8. chdir($directory);
  9. }
  10. require_once("boot.php");
  11. function poller_run($argv, $argc){
  12. global $a, $db;
  13. if(is_null($a)) {
  14. $a = new App;
  15. }
  16. if(is_null($db)) {
  17. @include(".htconfig.php");
  18. require_once("include/dba.php");
  19. $db = new dba($db_host, $db_user, $db_pass, $db_data);
  20. unset($db_host, $db_user, $db_pass, $db_data);
  21. };
  22. Config::load();
  23. // Quit when in maintenance
  24. if (Config::get('system', 'maintenance', true)) {
  25. return;
  26. }
  27. $a->set_baseurl(Config::get('system', 'url'));
  28. load_hooks();
  29. $a->start_process();
  30. if ($a->min_memory_reached()) {
  31. return;
  32. }
  33. if (poller_max_connections_reached()) {
  34. return;
  35. }
  36. if ($a->maxload_reached()) {
  37. return;
  38. }
  39. if(($argc <= 1) OR ($argv[1] != "no_cron")) {
  40. poller_run_cron();
  41. }
  42. if ($a->max_processes_reached()) {
  43. return;
  44. }
  45. // Checking the number of workers
  46. if (poller_too_much_workers()) {
  47. poller_kill_stale_workers();
  48. return;
  49. }
  50. $starttime = time();
  51. while ($r = poller_worker_process()) {
  52. // Check free memory
  53. if ($a->min_memory_reached()) {
  54. return;
  55. }
  56. // Count active workers and compare them with a maximum value that depends on the load
  57. if (poller_too_much_workers()) {
  58. return;
  59. }
  60. if (!poller_execute($r[0])) {
  61. return;
  62. }
  63. // Quit the poller once every hour
  64. if (time() > ($starttime + 3600))
  65. return;
  66. }
  67. }
  68. /**
  69. * @brief Execute a worker entry
  70. *
  71. * @param array $queue Workerqueue entry
  72. *
  73. * @return boolean "true" if further processing should be stopped
  74. */
  75. function poller_execute($queue) {
  76. $a = get_app();
  77. $mypid = getmypid();
  78. // Quit when in maintenance
  79. if (Config::get('system', 'maintenance', true)) {
  80. return false;
  81. }
  82. // Constantly check the number of parallel database processes
  83. if ($a->max_processes_reached()) {
  84. return false;
  85. }
  86. // Constantly check the number of available database connections to let the frontend be accessible at any time
  87. if (poller_max_connections_reached()) {
  88. return false;
  89. }
  90. $upd = q("UPDATE `workerqueue` SET `executed` = '%s', `pid` = %d WHERE `id` = %d AND `pid` = 0",
  91. dbesc(datetime_convert()),
  92. intval($mypid),
  93. intval($queue["id"]));
  94. if (!$upd) {
  95. logger("Couldn't update queue entry ".$queue["id"]." - skip this execution", LOGGER_DEBUG);
  96. q("COMMIT");
  97. return true;
  98. }
  99. // Assure that there are no tasks executed twice
  100. $id = q("SELECT `pid`, `executed` FROM `workerqueue` WHERE `id` = %d", intval($queue["id"]));
  101. if (!$id) {
  102. logger("Queue item ".$queue["id"]." vanished - skip this execution", LOGGER_DEBUG);
  103. q("COMMIT");
  104. return true;
  105. } elseif ((strtotime($id[0]["executed"]) <= 0) OR ($id[0]["pid"] == 0)) {
  106. logger("Entry for queue item ".$queue["id"]." wasn't stored - skip this execution", LOGGER_DEBUG);
  107. q("COMMIT");
  108. return true;
  109. } elseif ($id[0]["pid"] != $mypid) {
  110. logger("Queue item ".$queue["id"]." is to be executed by process ".$id[0]["pid"]." and not by me (".$mypid.") - skip this execution", LOGGER_DEBUG);
  111. q("COMMIT");
  112. return true;
  113. }
  114. q("COMMIT");
  115. $argv = json_decode($queue["parameter"]);
  116. // Check for existance and validity of the include file
  117. $include = $argv[0];
  118. if (!validate_include($include)) {
  119. logger("Include file ".$argv[0]." is not valid!");
  120. q("DELETE FROM `workerqueue` WHERE `id` = %d", intval($queue["id"]));
  121. return true;
  122. }
  123. require_once($include);
  124. $funcname = str_replace(".php", "", basename($argv[0]))."_run";
  125. if (function_exists($funcname)) {
  126. poller_exec_function($queue, $funcname, $argv);
  127. q("DELETE FROM `workerqueue` WHERE `id` = %d", intval($queue["id"]));
  128. } else {
  129. logger("Function ".$funcname." does not exist");
  130. }
  131. return true;
  132. }
  133. /**
  134. * @brief Execute a function from the queue
  135. *
  136. * @param array $queue Workerqueue entry
  137. * @param string $funcname name of the function
  138. * @param array $argv Array of values to be passed to the function
  139. */
  140. function poller_exec_function($queue, $funcname, $argv) {
  141. $a = get_app();
  142. $mypid = getmypid();
  143. $argc = count($argv);
  144. logger("Process ".$mypid." - Prio ".$queue["priority"]." - ID ".$queue["id"].": ".$funcname." ".$queue["parameter"]);
  145. $stamp = (float)microtime(true);
  146. // We use the callstack here to analyze the performance of executed worker entries.
  147. // For this reason the variables have to be initialized.
  148. if (Config::get("system", "profiler")) {
  149. $a->performance["start"] = microtime(true);
  150. $a->performance["database"] = 0;
  151. $a->performance["database_write"] = 0;
  152. $a->performance["network"] = 0;
  153. $a->performance["file"] = 0;
  154. $a->performance["rendering"] = 0;
  155. $a->performance["parser"] = 0;
  156. $a->performance["marktime"] = 0;
  157. $a->performance["markstart"] = microtime(true);
  158. $a->callstack = array();
  159. }
  160. // For better logging create a new process id for every worker call
  161. // But preserve the old one for the worker
  162. $old_process_id = $a->process_id;
  163. $a->process_id = uniqid("wrk", true);
  164. $funcname($argv, $argc);
  165. $a->process_id = $old_process_id;
  166. $duration = number_format(microtime(true) - $stamp, 3);
  167. if ($duration > 3600) {
  168. logger("Prio ".$queue["priority"].": ".$queue["parameter"]." - longer than 1 hour (".round($duration/60, 3).")", LOGGER_DEBUG);
  169. } elseif ($duration > 600) {
  170. logger("Prio ".$queue["priority"].": ".$queue["parameter"]." - longer than 10 minutes (".round($duration/60, 3).")", LOGGER_DEBUG);
  171. } elseif ($duration > 300) {
  172. logger("Prio ".$queue["priority"].": ".$queue["parameter"]." - longer than 5 minutes (".round($duration/60, 3).")", LOGGER_DEBUG);
  173. } elseif ($duration > 120) {
  174. logger("Prio ".$queue["priority"].": ".$queue["parameter"]." - longer than 2 minutes (".round($duration/60, 3).")", LOGGER_DEBUG);
  175. }
  176. logger("Process ".$mypid." - Prio ".$queue["priority"]." - ID ".$queue["id"].": ".$funcname." - done in ".$duration." seconds.");
  177. // Write down the performance values into the log
  178. if (Config::get("system", "profiler")) {
  179. $duration = microtime(true)-$a->performance["start"];
  180. if (Config::get("rendertime", "callstack")) {
  181. if (isset($a->callstack["database"])) {
  182. $o = "\nDatabase Read:\n";
  183. foreach ($a->callstack["database"] AS $func => $time) {
  184. $time = round($time, 3);
  185. if ($time > 0)
  186. $o .= $func.": ".$time."\n";
  187. }
  188. }
  189. if (isset($a->callstack["database_write"])) {
  190. $o .= "\nDatabase Write:\n";
  191. foreach ($a->callstack["database_write"] AS $func => $time) {
  192. $time = round($time, 3);
  193. if ($time > 0)
  194. $o .= $func.": ".$time."\n";
  195. }
  196. }
  197. if (isset($a->callstack["network"])) {
  198. $o .= "\nNetwork:\n";
  199. foreach ($a->callstack["network"] AS $func => $time) {
  200. $time = round($time, 3);
  201. if ($time > 0)
  202. $o .= $func.": ".$time."\n";
  203. }
  204. }
  205. } else {
  206. $o = '';
  207. }
  208. logger("ID ".$queue["id"].": ".$funcname.": ".sprintf("DB: %s/%s, Net: %s, I/O: %s, Other: %s, Total: %s".$o,
  209. number_format($a->performance["database"] - $a->performance["database_write"], 2),
  210. number_format($a->performance["database_write"], 2),
  211. number_format($a->performance["network"], 2),
  212. number_format($a->performance["file"], 2),
  213. number_format($duration - ($a->performance["database"] + $a->performance["network"] + $a->performance["file"]), 2),
  214. number_format($duration, 2)),
  215. LOGGER_DEBUG);
  216. }
  217. $cooldown = Config::get("system", "worker_cooldown", 0);
  218. if ($cooldown > 0) {
  219. logger("Process ".$mypid." - Prio ".$queue["priority"]." - ID ".$queue["id"].": ".$funcname." - in cooldown for ".$cooldown." seconds");
  220. sleep($cooldown);
  221. }
  222. }
  223. /**
  224. * @brief Checks if the number of database connections has reached a critical limit.
  225. *
  226. * @return bool Are more than 3/4 of the maximum connections used?
  227. */
  228. function poller_max_connections_reached() {
  229. // Fetch the max value from the config. This is needed when the system cannot detect the correct value by itself.
  230. $max = Config::get("system", "max_connections");
  231. // Fetch the percentage level where the poller will get active
  232. $maxlevel = Config::get("system", "max_connections_level", 75);
  233. if ($max == 0) {
  234. // the maximum number of possible user connections can be a system variable
  235. $r = q("SHOW VARIABLES WHERE `variable_name` = 'max_user_connections'");
  236. if ($r)
  237. $max = $r[0]["Value"];
  238. // Or it can be granted. This overrides the system variable
  239. $r = q("SHOW GRANTS");
  240. if ($r)
  241. foreach ($r AS $grants) {
  242. $grant = array_pop($grants);
  243. if (stristr($grant, "GRANT USAGE ON"))
  244. if (preg_match("/WITH MAX_USER_CONNECTIONS (\d*)/", $grant, $match))
  245. $max = $match[1];
  246. }
  247. }
  248. // If $max is set we will use the processlist to determine the current number of connections
  249. // The processlist only shows entries of the current user
  250. if ($max != 0) {
  251. $r = q("SHOW PROCESSLIST");
  252. if (!dbm::is_result($r))
  253. return false;
  254. $used = count($r);
  255. logger("Connection usage (user values): ".$used."/".$max, LOGGER_DEBUG);
  256. $level = ($used / $max) * 100;
  257. if ($level >= $maxlevel) {
  258. logger("Maximum level (".$maxlevel."%) of user connections reached: ".$used."/".$max);
  259. return true;
  260. }
  261. }
  262. // We will now check for the system values.
  263. // This limit could be reached although the user limits are fine.
  264. $r = q("SHOW VARIABLES WHERE `variable_name` = 'max_connections'");
  265. if (!$r)
  266. return false;
  267. $max = intval($r[0]["Value"]);
  268. if ($max == 0)
  269. return false;
  270. $r = q("SHOW STATUS WHERE `variable_name` = 'Threads_connected'");
  271. if (!$r)
  272. return false;
  273. $used = intval($r[0]["Value"]);
  274. if ($used == 0)
  275. return false;
  276. logger("Connection usage (system values): ".$used."/".$max, LOGGER_DEBUG);
  277. $level = $used / $max * 100;
  278. if ($level < $maxlevel)
  279. return false;
  280. logger("Maximum level (".$level."%) of system connections reached: ".$used."/".$max);
  281. return true;
  282. }
  283. /**
  284. * @brief fix the queue entry if the worker process died
  285. *
  286. */
  287. function poller_kill_stale_workers() {
  288. $r = q("SELECT `pid`, `executed`, `priority`, `parameter` FROM `workerqueue` WHERE `executed` > '%s'", dbesc(NULL_DATE));
  289. if (!dbm::is_result($r)) {
  290. // No processing here needed
  291. return;
  292. }
  293. foreach ($r AS $pid) {
  294. if (!posix_kill($pid["pid"], 0)) {
  295. q("UPDATE `workerqueue` SET `executed` = '%s', `pid` = 0 WHERE `pid` = %d",
  296. dbesc(NULL_DATE), intval($pid["pid"]));
  297. } else {
  298. // Kill long running processes
  299. // Check if the priority is in a valid range
  300. if (!in_array($pid["priority"], array(PRIORITY_CRITICAL, PRIORITY_HIGH, PRIORITY_MEDIUM, PRIORITY_LOW, PRIORITY_NEGLIGIBLE)))
  301. $pid["priority"] = PRIORITY_MEDIUM;
  302. // Define the maximum durations
  303. $max_duration_defaults = array(PRIORITY_CRITICAL => 360, PRIORITY_HIGH => 10, PRIORITY_MEDIUM => 60, PRIORITY_LOW => 180, PRIORITY_NEGLIGIBLE => 360);
  304. $max_duration = $max_duration_defaults[$pid["priority"]];
  305. $argv = json_decode($pid["parameter"]);
  306. $argv[0] = basename($argv[0]);
  307. // How long is the process already running?
  308. $duration = (time() - strtotime($pid["executed"])) / 60;
  309. if ($duration > $max_duration) {
  310. logger("Worker process ".$pid["pid"]." (".implode(" ", $argv).") took more than ".$max_duration." minutes. It will be killed now.");
  311. posix_kill($pid["pid"], SIGTERM);
  312. // We killed the stale process.
  313. // To avoid a blocking situation we reschedule the process at the beginning of the queue.
  314. // Additionally we are lowering the priority.
  315. q("UPDATE `workerqueue` SET `executed` = '%s', `created` = '%s',
  316. `priority` = %d, `pid` = 0 WHERE `pid` = %d",
  317. dbesc(NULL_DATE),
  318. dbesc(datetime_convert()),
  319. intval(PRIORITY_NEGLIGIBLE),
  320. intval($pid["pid"]));
  321. } else {
  322. logger("Worker process ".$pid["pid"]." (".implode(" ", $argv).") now runs for ".round($duration)." of ".$max_duration." allowed minutes. That's okay.", LOGGER_DEBUG);
  323. }
  324. }
  325. }
  326. }
  327. /**
  328. * @brief Checks if the number of active workers exceeds the given limits
  329. *
  330. * @return bool Are there too much workers running?
  331. */
  332. function poller_too_much_workers() {
  333. $queues = Config::get("system", "worker_queues", 4);
  334. $maxqueues = $queues;
  335. $active = poller_active_workers();
  336. // Decrease the number of workers at higher load
  337. $load = current_load();
  338. if($load) {
  339. $maxsysload = intval(Config::get("system", "maxloadavg", 50));
  340. $maxworkers = $queues;
  341. // Some magical mathemathics to reduce the workers
  342. $exponent = 3;
  343. $slope = $maxworkers / pow($maxsysload, $exponent);
  344. $queues = ceil($slope * pow(max(0, $maxsysload - $load), $exponent));
  345. $s = q("SELECT COUNT(*) AS `total` FROM `workerqueue` WHERE `executed` <= '%s'", dbesc(NULL_DATE));
  346. $entries = $s[0]["total"];
  347. if (Config::get("system", "worker_fastlane", false) AND ($queues > 0) AND ($entries > 0) AND ($active >= $queues)) {
  348. $s = q("SELECT `priority` FROM `workerqueue` WHERE `executed` <= '%s' ORDER BY `priority` LIMIT 1", dbesc(NULL_DATE));
  349. $top_priority = $s[0]["priority"];
  350. $s = q("SELECT `id` FROM `workerqueue` WHERE `priority` <= %d AND `executed` > '%s' LIMIT 1",
  351. intval($top_priority), dbesc(NULL_DATE));
  352. $high_running = dbm::is_result($s);
  353. if (!$high_running AND ($top_priority > PRIORITY_UNDEFINED) AND ($top_priority < PRIORITY_NEGLIGIBLE)) {
  354. logger("There are jobs with priority ".$top_priority." waiting but none is executed. Open a fastlane.", LOGGER_DEBUG);
  355. $queues = $active + 1;
  356. }
  357. }
  358. // Create a list of queue entries grouped by their priority
  359. $running = array(PRIORITY_CRITICAL => 0,
  360. PRIORITY_HIGH => 0,
  361. PRIORITY_MEDIUM => 0,
  362. PRIORITY_LOW => 0,
  363. PRIORITY_NEGLIGIBLE => 0);
  364. $r = q("SELECT COUNT(*) AS `running`, `priority` FROM `process` INNER JOIN `workerqueue` ON `workerqueue`.`pid` = `process`.`pid` GROUP BY `priority`");
  365. if (dbm::is_result($r))
  366. foreach ($r AS $process)
  367. $running[$process["priority"]] = $process["running"];
  368. $processlist = "";
  369. $r = q("SELECT COUNT(*) AS `entries`, `priority` FROM `workerqueue` GROUP BY `priority`");
  370. if (dbm::is_result($r))
  371. foreach ($r as $entry) {
  372. if ($processlist != "")
  373. $processlist .= ", ";
  374. $processlist .= $entry["priority"].":".$running[$entry["priority"]]."/".$entry["entries"];
  375. }
  376. logger("Load: ".$load."/".$maxsysload." - processes: ".$active."/".$entries." (".$processlist.") - maximum: ".$queues."/".$maxqueues, LOGGER_DEBUG);
  377. // Are there fewer workers running as possible? Then fork a new one.
  378. if (!Config::get("system", "worker_dont_fork") AND ($queues > ($active + 1)) AND ($entries > 1)) {
  379. logger("Active workers: ".$active."/".$queues." Fork a new worker.", LOGGER_DEBUG);
  380. $args = array("include/poller.php", "no_cron");
  381. $a = get_app();
  382. $a->proc_run($args);
  383. }
  384. }
  385. return($active >= $queues);
  386. }
  387. /**
  388. * @brief Returns the number of active poller processes
  389. *
  390. * @return integer Number of active poller processes
  391. */
  392. function poller_active_workers() {
  393. $workers = q("SELECT COUNT(*) AS `processes` FROM `process` WHERE `command` = 'poller.php'");
  394. return($workers[0]["processes"]);
  395. }
  396. /**
  397. * @brief Check if we should pass some slow processes
  398. *
  399. * When the active processes of the highest priority are using more than 2/3
  400. * of all processes, we let pass slower processes.
  401. *
  402. * @param string $highest_priority Returns the currently highest priority
  403. * @return bool We let pass a slower process than $highest_priority
  404. */
  405. function poller_passing_slow(&$highest_priority) {
  406. $highest_priority = 0;
  407. $r = q("SELECT `priority`
  408. FROM `process`
  409. INNER JOIN `workerqueue` ON `workerqueue`.`pid` = `process`.`pid`");
  410. // No active processes at all? Fine
  411. if (!dbm::is_result($r))
  412. return(false);
  413. $priorities = array();
  414. foreach ($r AS $line)
  415. $priorities[] = $line["priority"];
  416. // Should not happen
  417. if (count($priorities) == 0)
  418. return(false);
  419. $highest_priority = min($priorities);
  420. // The highest process is already the slowest one?
  421. // Then we quit
  422. if ($highest_priority == PRIORITY_NEGLIGIBLE)
  423. return(false);
  424. $high = 0;
  425. foreach ($priorities AS $priority)
  426. if ($priority == $highest_priority)
  427. ++$high;
  428. logger("Highest priority: ".$highest_priority." Total processes: ".count($priorities)." Count high priority processes: ".$high, LOGGER_DEBUG);
  429. $passing_slow = (($high/count($priorities)) > (2/3));
  430. if ($passing_slow)
  431. logger("Passing slower processes than priority ".$highest_priority, LOGGER_DEBUG);
  432. return($passing_slow);
  433. }
  434. /**
  435. * @brief Returns the next worker process
  436. *
  437. * @return string SQL statement
  438. */
  439. function poller_worker_process() {
  440. q("START TRANSACTION;");
  441. // Check if we should pass some low priority process
  442. $highest_priority = 0;
  443. if (poller_passing_slow($highest_priority)) {
  444. // Are there waiting processes with a higher priority than the currently highest?
  445. $r = q("SELECT * FROM `workerqueue`
  446. WHERE `executed` <= '%s' AND `priority` < %d
  447. ORDER BY `priority`, `created` LIMIT 1",
  448. dbesc(NULL_DATE),
  449. intval($highest_priority));
  450. if (dbm::is_result($r)) {
  451. return $r;
  452. }
  453. // Give slower processes some processing time
  454. $r = q("SELECT * FROM `workerqueue`
  455. WHERE `executed` <= '%s' AND `priority` > %d
  456. ORDER BY `priority`, `created` LIMIT 1",
  457. dbesc(NULL_DATE),
  458. intval($highest_priority));
  459. }
  460. // If there is no result (or we shouldn't pass lower processes) we check without priority limit
  461. if (($highest_priority == 0) OR !dbm::is_result($r)) {
  462. $r = q("SELECT * FROM `workerqueue` WHERE `executed` <= '%s' ORDER BY `priority`, `created` LIMIT 1", dbesc(NULL_DATE));
  463. }
  464. return $r;
  465. }
  466. /**
  467. * @brief Call the front end worker
  468. */
  469. function call_worker() {
  470. if (!Config::get("system", "frontend_worker")) {
  471. return;
  472. }
  473. $url = App::get_baseurl()."/worker";
  474. fetch_url($url, false, $redirects, 1);
  475. }
  476. /**
  477. * @brief Call the front end worker if there aren't any active
  478. */
  479. function call_worker_if_idle() {
  480. if (!Config::get("system", "frontend_worker")) {
  481. return;
  482. }
  483. // Do we have "proc_open"? Then we can fork the poller
  484. if (function_exists("proc_open")) {
  485. // When was the last time that we called the worker?
  486. // Less than one minute? Then we quit
  487. if ((time() - Config::get("system", "worker_started")) < 60) {
  488. return;
  489. }
  490. set_config("system", "worker_started", time());
  491. // Do we have enough running workers? Then we quit here.
  492. if (poller_too_much_workers()) {
  493. // Cleaning dead processes
  494. poller_kill_stale_workers();
  495. get_app()->remove_inactive_processes();
  496. return;
  497. }
  498. poller_run_cron();
  499. logger('Call poller', LOGGER_DEBUG);
  500. $args = array("include/poller.php", "no_cron");
  501. $a = get_app();
  502. $a->proc_run($args);
  503. return;
  504. }
  505. // We cannot execute background processes.
  506. // We now run the processes from the frontend.
  507. // This won't work with long running processes.
  508. poller_run_cron();
  509. clear_worker_processes();
  510. $workers = q("SELECT COUNT(*) AS `processes` FROM `process` WHERE `command` = 'worker.php'");
  511. if ($workers[0]["processes"] == 0) {
  512. call_worker();
  513. }
  514. }
  515. /**
  516. * @brief Removes long running worker processes
  517. */
  518. function clear_worker_processes() {
  519. $timeout = Config::get("system", "frontend_worker_timeout", 10);
  520. /// @todo We should clean up the corresponding workerqueue entries as well
  521. q("DELETE FROM `process` WHERE `created` < '%s' AND `command` = 'worker.php'",
  522. dbesc(datetime_convert('UTC','UTC',"now - ".$timeout." minutes")));
  523. }
  524. /**
  525. * @brief Runs the cron processes
  526. */
  527. function poller_run_cron() {
  528. logger('Add cron entries', LOGGER_DEBUG);
  529. // Check for spooled items
  530. proc_run(PRIORITY_HIGH, "include/spool_post.php");
  531. // Run the cron job that calls all other jobs
  532. proc_run(PRIORITY_MEDIUM, "include/cron.php");
  533. // Run the cronhooks job separately from cron for being able to use a different timing
  534. proc_run(PRIORITY_MEDIUM, "include/cronhooks.php");
  535. // Cleaning dead processes
  536. poller_kill_stale_workers();
  537. }
  538. if (array_search(__file__,get_included_files())===0){
  539. poller_run($_SERVER["argv"],$_SERVER["argc"]);
  540. get_app()->end_process();
  541. killme();
  542. }
  543. ?>