mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-22 06:42:42 +01:00
Make ./bin/aphlict
behave more like a service.
Summary: Fixes T5126. Provide `start`, `stop`, `restart`, `debug` and `status` workflows for `./bin/aphlict`. This makes it easier to manage Aphlict as if it were a service. Test Plan: ``` > sudo ./bin/aphlict status Aphlict is not running. > sudo ./bin/aphlict stop Aphlict is not running. > sudo ./bin/aphlict start Aphlict Server started. > sudo ./bin/aphlict status Aphlict (12880) is running. > sudo ./bin/aphlict restart Stopping Aphlict Server (12880)... Aphlict Server (12880) exited normally. Aphlict Server started. > sudo ./bin/aphlict stop Stopping Aphlict Server (12895)... Aphlict Server (12895) exited normally. > sudo ./bin/aphlict debug Starting Aphlict server in foreground... Launching server: $ node '/usr/src/phabricator/src/applications/aphlict/management/../../../../support/aphlict/server/aphlict_server.js' --port='22280' --admin='22281' --host='localhost' --user='aphlict' [Fri May 30 2014 09:56:14 GMT+0000 (UTC)] Started Server (PID 12911) ``` Reviewers: #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: hach-que, epriestley, Korvin Maniphest Tasks: T5126 Differential Revision: https://secure.phabricator.com/D9226
This commit is contained in:
parent
fe98aa6839
commit
8a7a7dcbf1
8 changed files with 333 additions and 153 deletions
|
@ -1105,6 +1105,12 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorActionView' => 'view/layout/PhabricatorActionView.php',
|
'PhabricatorActionView' => 'view/layout/PhabricatorActionView.php',
|
||||||
'PhabricatorAllCapsTranslation' => 'infrastructure/internationalization/translation/PhabricatorAllCapsTranslation.php',
|
'PhabricatorAllCapsTranslation' => 'infrastructure/internationalization/translation/PhabricatorAllCapsTranslation.php',
|
||||||
'PhabricatorAnchorView' => 'view/layout/PhabricatorAnchorView.php',
|
'PhabricatorAnchorView' => 'view/layout/PhabricatorAnchorView.php',
|
||||||
|
'PhabricatorAphlictManagementDebugWorkflow' => 'applications/aphlict/management/PhabricatorAphlictManagementDebugWorkflow.php',
|
||||||
|
'PhabricatorAphlictManagementRestartWorkflow' => 'applications/aphlict/management/PhabricatorAphlictManagementRestartWorkflow.php',
|
||||||
|
'PhabricatorAphlictManagementStartWorkflow' => 'applications/aphlict/management/PhabricatorAphlictManagementStartWorkflow.php',
|
||||||
|
'PhabricatorAphlictManagementStatusWorkflow' => 'applications/aphlict/management/PhabricatorAphlictManagementStatusWorkflow.php',
|
||||||
|
'PhabricatorAphlictManagementStopWorkflow' => 'applications/aphlict/management/PhabricatorAphlictManagementStopWorkflow.php',
|
||||||
|
'PhabricatorAphlictManagementWorkflow' => 'applications/aphlict/management/PhabricatorAphlictManagementWorkflow.php',
|
||||||
'PhabricatorAphrontBarExample' => 'applications/uiexample/examples/PhabricatorAphrontBarExample.php',
|
'PhabricatorAphrontBarExample' => 'applications/uiexample/examples/PhabricatorAphrontBarExample.php',
|
||||||
'PhabricatorAphrontViewTestCase' => 'view/__tests__/PhabricatorAphrontViewTestCase.php',
|
'PhabricatorAphrontViewTestCase' => 'view/__tests__/PhabricatorAphrontViewTestCase.php',
|
||||||
'PhabricatorAppSearchEngine' => 'applications/meta/query/PhabricatorAppSearchEngine.php',
|
'PhabricatorAppSearchEngine' => 'applications/meta/query/PhabricatorAppSearchEngine.php',
|
||||||
|
@ -3871,6 +3877,12 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorActionView' => 'AphrontView',
|
'PhabricatorActionView' => 'AphrontView',
|
||||||
'PhabricatorAllCapsTranslation' => 'PhabricatorTranslation',
|
'PhabricatorAllCapsTranslation' => 'PhabricatorTranslation',
|
||||||
'PhabricatorAnchorView' => 'AphrontView',
|
'PhabricatorAnchorView' => 'AphrontView',
|
||||||
|
'PhabricatorAphlictManagementDebugWorkflow' => 'PhabricatorAphlictManagementWorkflow',
|
||||||
|
'PhabricatorAphlictManagementRestartWorkflow' => 'PhabricatorAphlictManagementWorkflow',
|
||||||
|
'PhabricatorAphlictManagementStartWorkflow' => 'PhabricatorAphlictManagementWorkflow',
|
||||||
|
'PhabricatorAphlictManagementStatusWorkflow' => 'PhabricatorAphlictManagementWorkflow',
|
||||||
|
'PhabricatorAphlictManagementStopWorkflow' => 'PhabricatorAphlictManagementWorkflow',
|
||||||
|
'PhabricatorAphlictManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
||||||
'PhabricatorAphrontBarExample' => 'PhabricatorUIExample',
|
'PhabricatorAphrontBarExample' => 'PhabricatorUIExample',
|
||||||
'PhabricatorAphrontViewTestCase' => 'PhabricatorTestCase',
|
'PhabricatorAphrontViewTestCase' => 'PhabricatorTestCase',
|
||||||
'PhabricatorAppSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
'PhabricatorAppSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorAphlictManagementDebugWorkflow
|
||||||
|
extends PhabricatorAphlictManagementWorkflow {
|
||||||
|
|
||||||
|
public function didConstruct() {
|
||||||
|
$this
|
||||||
|
->setName('debug')
|
||||||
|
->setSynopsis(
|
||||||
|
pht(
|
||||||
|
'Start the notifications server in the foreground and print large '.
|
||||||
|
'volumes of diagnostic information to the console.'))
|
||||||
|
->setArguments(array());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute(PhutilArgumentParser $args) {
|
||||||
|
$this->willLaunch();
|
||||||
|
return $this->launch(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorAphlictManagementRestartWorkflow
|
||||||
|
extends PhabricatorAphlictManagementWorkflow {
|
||||||
|
|
||||||
|
public function didConstruct() {
|
||||||
|
$this
|
||||||
|
->setName('restart')
|
||||||
|
->setSynopsis(pht('Stop, then start the notifications server.'))
|
||||||
|
->setArguments(array());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute(PhutilArgumentParser $args) {
|
||||||
|
$err = $this->executeStopCommand();
|
||||||
|
if ($err) {
|
||||||
|
return $err;
|
||||||
|
}
|
||||||
|
return $this->executeStartCommand();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorAphlictManagementStartWorkflow
|
||||||
|
extends PhabricatorAphlictManagementWorkflow {
|
||||||
|
|
||||||
|
public function didConstruct() {
|
||||||
|
$this
|
||||||
|
->setName('start')
|
||||||
|
->setSynopsis(pht('Start the notifications server.'))
|
||||||
|
->setArguments(array());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute(PhutilArgumentParser $args) {
|
||||||
|
return $this->executeStartCommand();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorAphlictManagementStatusWorkflow
|
||||||
|
extends PhabricatorAphlictManagementWorkflow {
|
||||||
|
|
||||||
|
public function didConstruct() {
|
||||||
|
$this
|
||||||
|
->setName('status')
|
||||||
|
->setSynopsis(pht('Show the status of the notifications server.'))
|
||||||
|
->setArguments(array());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute(PhutilArgumentParser $args) {
|
||||||
|
$console = PhutilConsole::getConsole();
|
||||||
|
$pid = $this->getPID();
|
||||||
|
|
||||||
|
if (!$pid) {
|
||||||
|
$console->writeErr(pht("Aphlict is not running.\n"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$console->writeOut(pht("Aphlict (%s) is running.\n", $pid));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorAphlictManagementStopWorkflow
|
||||||
|
extends PhabricatorAphlictManagementWorkflow {
|
||||||
|
|
||||||
|
public function didConstruct() {
|
||||||
|
$this
|
||||||
|
->setName('stop')
|
||||||
|
->setSynopsis(pht('Stop the notifications server.'))
|
||||||
|
->setArguments(array());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute(PhutilArgumentParser $args) {
|
||||||
|
return $this->executeStopCommand();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,204 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class PhabricatorAphlictManagementWorkflow
|
||||||
|
extends PhabricatorManagementWorkflow {
|
||||||
|
|
||||||
|
final public function getPIDPath() {
|
||||||
|
return PhabricatorEnv::getEnvConfig('notification.pidfile');
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function getPID() {
|
||||||
|
$pid = null;
|
||||||
|
if (Filesystem::pathExists($this->getPIDPath())) {
|
||||||
|
$pid = (int)Filesystem::readFile($this->getPIDPath());
|
||||||
|
}
|
||||||
|
return $pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function cleanup($signo = '?') {
|
||||||
|
global $g_future;
|
||||||
|
if ($g_future) {
|
||||||
|
$g_future->resolveKill();
|
||||||
|
$g_future = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Filesystem::remove($this->getPIDPath());
|
||||||
|
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function requireExtensions() {
|
||||||
|
self::mustHaveExtension('pcntl');
|
||||||
|
self::mustHaveExtension('posix');
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function mustHaveExtension($ext) {
|
||||||
|
if (!extension_loaded($ext)) {
|
||||||
|
echo "ERROR: The PHP extension '{$ext}' is not installed. You must ".
|
||||||
|
"install it to run aphlict on this machine.\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$extension = new ReflectionExtension($ext);
|
||||||
|
foreach ($extension->getFunctions() as $function) {
|
||||||
|
$function = $function->name;
|
||||||
|
if (!function_exists($function)) {
|
||||||
|
echo "ERROR: The PHP function {$function}() is disabled. You must ".
|
||||||
|
"enable it to run aphlict on this machine.\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final protected function willLaunch() {
|
||||||
|
$console = PhutilConsole::getConsole();
|
||||||
|
|
||||||
|
$pid = $this->getPID();
|
||||||
|
if ($pid) {
|
||||||
|
$console->writeErr(
|
||||||
|
"Unable to start notifications server because it is already ".
|
||||||
|
"running.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (posix_getuid() != 0) {
|
||||||
|
$console->writeErr(
|
||||||
|
"You must run this script as root; the Aphlict server needs to bind ".
|
||||||
|
"to privileged ports.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Filesystem::binaryExists('node')) {
|
||||||
|
$console->writeErr(
|
||||||
|
"`node` is not in \$PATH. You must install Node.js to run the Aphlict ".
|
||||||
|
"server.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final protected function launch($debug = false) {
|
||||||
|
$console = PhutilConsole::getConsole();
|
||||||
|
|
||||||
|
if ($debug) {
|
||||||
|
$console->writeOut(pht("Starting Aphlict server in foreground...\n"));
|
||||||
|
} else {
|
||||||
|
Filesystem::writeFile($this->getPIDPath(), getmypid());
|
||||||
|
}
|
||||||
|
|
||||||
|
$server_uri = PhabricatorEnv::getEnvConfig('notification.server-uri');
|
||||||
|
$server_uri = new PhutilURI($server_uri);
|
||||||
|
|
||||||
|
$client_uri = PhabricatorEnv::getEnvConfig('notification.client-uri');
|
||||||
|
$client_uri = new PhutilURI($client_uri);
|
||||||
|
|
||||||
|
$user = PhabricatorEnv::getEnvConfig('notification.user');
|
||||||
|
$log = PhabricatorEnv::getEnvConfig('notification.log');
|
||||||
|
|
||||||
|
$server_argv = array();
|
||||||
|
$server_argv[] = csprintf('--port=%s', $client_uri->getPort());
|
||||||
|
$server_argv[] = csprintf('--admin=%s', $server_uri->getPort());
|
||||||
|
$server_argv[] = csprintf('--host=%s', $server_uri->getDomain());
|
||||||
|
|
||||||
|
if ($user) {
|
||||||
|
$server_argv[] = csprintf('--user=%s', $user);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$debug) {
|
||||||
|
$server_argv[] = csprintf('--log=%s', $log);
|
||||||
|
}
|
||||||
|
|
||||||
|
$command = csprintf(
|
||||||
|
'node %s %C',
|
||||||
|
dirname(__FILE__).'/../../../../support/aphlict/server/aphlict_server.js',
|
||||||
|
implode(' ', $server_argv));
|
||||||
|
|
||||||
|
if (!$debug) {
|
||||||
|
declare(ticks = 1);
|
||||||
|
pcntl_signal(SIGINT, array($this, 'cleanup'));
|
||||||
|
pcntl_signal(SIGTERM, array($this, 'cleanup'));
|
||||||
|
}
|
||||||
|
register_shutdown_function(array($this, 'cleanup'));
|
||||||
|
|
||||||
|
if ($debug) {
|
||||||
|
$console->writeOut("Launching server:\n\n $ ".$command."\n\n");
|
||||||
|
|
||||||
|
$err = phutil_passthru('%C', $command);
|
||||||
|
$console->writeOut(">>> Server exited!\n");
|
||||||
|
exit($err);
|
||||||
|
} else {
|
||||||
|
while (true) {
|
||||||
|
global $g_future;
|
||||||
|
$g_future = new ExecFuture('exec %C', $command);
|
||||||
|
$g_future->resolve();
|
||||||
|
|
||||||
|
// If the server exited, wait a couple of seconds and restart it.
|
||||||
|
unset($g_future);
|
||||||
|
sleep(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( Commands )----------------------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
final protected function executeStartCommand() {
|
||||||
|
$console = PhutilConsole::getConsole();
|
||||||
|
$this->willLaunch();
|
||||||
|
|
||||||
|
$pid = pcntl_fork();
|
||||||
|
if ($pid < 0) {
|
||||||
|
throw new Exception('Failed to fork()!');
|
||||||
|
} else if ($pid) {
|
||||||
|
$console->writeErr(pht("Aphlict Server started.\n"));
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// When we fork, the child process will inherit its parent's set of open
|
||||||
|
// file descriptors. If the parent process of bin/aphlict is waiting for
|
||||||
|
// bin/aphlict's file descriptors to close, it will be stuck waiting on
|
||||||
|
// the daemonized process. (This happens if e.g. bin/aphlict is started
|
||||||
|
// in another script using passthru().)
|
||||||
|
fclose(STDOUT);
|
||||||
|
fclose(STDERR);
|
||||||
|
|
||||||
|
$this->launch();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
final protected function executeStopCommand() {
|
||||||
|
$console = PhutilConsole::getConsole();
|
||||||
|
|
||||||
|
$pid = $this->getPID();
|
||||||
|
if (!$pid) {
|
||||||
|
$console->writeErr(pht("Aphlict is not running.\n"));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$console->writeErr(pht("Stopping Aphlict Server (%s)...\n", $pid));
|
||||||
|
posix_kill($pid, SIGINT);
|
||||||
|
|
||||||
|
$start = time();
|
||||||
|
do {
|
||||||
|
if (!PhabricatorDaemonReference::isProcessRunning($pid)) {
|
||||||
|
$console->writeOut(
|
||||||
|
"%s\n",
|
||||||
|
pht('Aphlict Server (%s) exited normally.', $pid));
|
||||||
|
$pid = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
usleep(100000);
|
||||||
|
} while (time() < $start + 5);
|
||||||
|
|
||||||
|
if ($pid) {
|
||||||
|
$console->writeErr(pht('Sending %s a SIGKILL.', $pid)."\n");
|
||||||
|
posix_kill($pid, SIGKILL);
|
||||||
|
unset($pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
Filesystem::remove($this->getPIDPath());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,164 +1,26 @@
|
||||||
#!/usr/bin/env php
|
#!/usr/bin/env php
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
// This is a launcher for the 'aphlict' Node.js notification server that
|
|
||||||
// provides real-time notifications for Phabricator. It handles reading
|
|
||||||
// configuration from the Phabricator config, daemonizing the server,
|
|
||||||
// restarting the server if it crashes, and some basic sanity checks.
|
|
||||||
|
|
||||||
|
|
||||||
$root = dirname(dirname(dirname(dirname(__FILE__))));
|
$root = dirname(dirname(dirname(dirname(__FILE__))));
|
||||||
require_once $root.'/scripts/__init_script__.php';
|
require_once $root.'/scripts/__init_script__.php';
|
||||||
|
|
||||||
|
PhabricatorAphlictManagementWorkflow::requireExtensions();
|
||||||
// >>> Options and Arguments ---------------------------------------------------
|
|
||||||
|
|
||||||
$args = new PhutilArgumentParser($argv);
|
$args = new PhutilArgumentParser($argv);
|
||||||
$args->setTagline('manage Aphlict notification server');
|
$args->setTagline('manage Aphlict notification server');
|
||||||
$args->setSynopsis(<<<EOHELP
|
$args->setSynopsis(<<<EOSYNOPSIS
|
||||||
**aphlict** [__options__]
|
**aphlict** __command__ [__options__]
|
||||||
Start (or restart) the Aphlict server.
|
Manage the Aphlict server.
|
||||||
EOHELP
|
|
||||||
);
|
EOSYNOPSIS
|
||||||
|
);
|
||||||
$args->parseStandardArguments();
|
$args->parseStandardArguments();
|
||||||
$args->parse(array(
|
|
||||||
array(
|
$args->parseWorkflows(array(
|
||||||
'name' => 'foreground',
|
new PhabricatorAphlictManagementStatusWorkflow(),
|
||||||
'help' => 'Run in the foreground instead of daemonizing.',
|
new PhabricatorAphlictManagementStartWorkflow(),
|
||||||
),
|
new PhabricatorAphlictManagementStopWorkflow(),
|
||||||
|
new PhabricatorAphlictManagementRestartWorkflow(),
|
||||||
|
new PhabricatorAphlictManagementDebugWorkflow(),
|
||||||
|
new PhutilHelpArgumentWorkflow(),
|
||||||
));
|
));
|
||||||
|
|
||||||
if (posix_getuid() != 0) {
|
|
||||||
throw new Exception(
|
|
||||||
"You must run this script as root; the Aphlict server needs to bind to ".
|
|
||||||
"privileged ports.");
|
|
||||||
}
|
|
||||||
|
|
||||||
list($err) = exec_manual('node -v');
|
|
||||||
if ($err) {
|
|
||||||
throw new Exception(
|
|
||||||
'`node` is not in $PATH. You must install Node.js to run the Aphlict '.
|
|
||||||
'server.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$server_uri = PhabricatorEnv::getEnvConfig('notification.server-uri');
|
|
||||||
$server_uri = new PhutilURI($server_uri);
|
|
||||||
|
|
||||||
$client_uri = PhabricatorEnv::getEnvConfig('notification.client-uri');
|
|
||||||
$client_uri = new PhutilURI($client_uri);
|
|
||||||
|
|
||||||
$user = PhabricatorEnv::getEnvConfig('notification.user');
|
|
||||||
$log = PhabricatorEnv::getEnvConfig('notification.log');
|
|
||||||
|
|
||||||
$g_pidfile = PhabricatorEnv::getEnvConfig('notification.pidfile');
|
|
||||||
$g_future = null;
|
|
||||||
|
|
||||||
$foreground = $args->getArg('foreground');
|
|
||||||
|
|
||||||
// Build the argument list for the server itself.
|
|
||||||
$server_argv = array();
|
|
||||||
$server_argv[] = csprintf('--port=%s', $client_uri->getPort());
|
|
||||||
$server_argv[] = csprintf('--admin=%s', $server_uri->getPort());
|
|
||||||
$server_argv[] = csprintf('--host=%s', $server_uri->getDomain());
|
|
||||||
|
|
||||||
if ($user) {
|
|
||||||
$server_argv[] = csprintf('--user=%s', $user);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($log) {
|
|
||||||
$server_argv[] = csprintf('--log=%s', $log);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// >>> Foreground / Background -------------------------------------------------
|
|
||||||
|
|
||||||
// If we start in the foreground, we use phutil_passthru() below to show any
|
|
||||||
// output from the server to the console, but this means *this* process won't
|
|
||||||
// receive signals until the child exits. If we write our pid to the pidfile
|
|
||||||
// and then another process starts, it will try to SIGTERM us but we won't
|
|
||||||
// receive the signal. Since the effect is the same and this is simpler, just
|
|
||||||
// ignore the pidfile if launched in `--foreground` mode; this is a debugging
|
|
||||||
// mode anyway.
|
|
||||||
if ($foreground) {
|
|
||||||
echo "Starting server in foreground, ignoring pidfile...\n";
|
|
||||||
$g_pidfile = null;
|
|
||||||
} else {
|
|
||||||
$pid = pcntl_fork();
|
|
||||||
if ($pid < 0) {
|
|
||||||
throw new Exception("Failed to fork()!");
|
|
||||||
} else if ($pid) {
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
// When we fork, the child process will inherit its parent's set of open
|
|
||||||
// file descriptors. If the parent process of bin/aphlict is waiting for
|
|
||||||
// bin/aphlict's file descriptors to close, it will be stuck waiting on
|
|
||||||
// the daemonized process. (This happens if e.g. bin/aphlict is started
|
|
||||||
// in another script using passthru().)
|
|
||||||
fclose(STDOUT);
|
|
||||||
fclose(STDERR);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// >>> Signals / Cleanup -------------------------------------------------------
|
|
||||||
|
|
||||||
function cleanup($sig = '?') {
|
|
||||||
global $g_pidfile;
|
|
||||||
if ($g_pidfile) {
|
|
||||||
Filesystem::remove($g_pidfile);
|
|
||||||
$g_pidfile = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
global $g_future;
|
|
||||||
if ($g_future) {
|
|
||||||
$g_future->resolveKill();
|
|
||||||
$g_future = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$foreground) {
|
|
||||||
declare(ticks = 1);
|
|
||||||
pcntl_signal(SIGTERM, 'cleanup');
|
|
||||||
}
|
|
||||||
|
|
||||||
register_shutdown_function('cleanup');
|
|
||||||
|
|
||||||
|
|
||||||
// >>> pidfile -----------------------------------------------------------------
|
|
||||||
|
|
||||||
if ($g_pidfile) {
|
|
||||||
if (Filesystem::pathExists($g_pidfile)) {
|
|
||||||
$old_pid = (int)Filesystem::readFile($g_pidfile);
|
|
||||||
posix_kill($old_pid, SIGTERM);
|
|
||||||
sleep(1);
|
|
||||||
Filesystem::remove($g_pidfile);
|
|
||||||
}
|
|
||||||
Filesystem::writeFile($g_pidfile, getmypid());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// >>> run ---------------------------------------------------------------------
|
|
||||||
|
|
||||||
$command = csprintf(
|
|
||||||
'node %s %C',
|
|
||||||
dirname(__FILE__).'/aphlict_server.js',
|
|
||||||
implode(' ', $server_argv));
|
|
||||||
|
|
||||||
if ($foreground) {
|
|
||||||
echo "Launching server:\n\n";
|
|
||||||
echo " $ ".$command."\n\n";
|
|
||||||
|
|
||||||
$err = phutil_passthru('%C', $command);
|
|
||||||
echo ">>> Server exited!\n";
|
|
||||||
exit($err);
|
|
||||||
} else {
|
|
||||||
while (true) {
|
|
||||||
$g_future = new ExecFuture('exec %C', $command);
|
|
||||||
$g_future->resolve();
|
|
||||||
|
|
||||||
// If the server exited, wait a couple of seconds and restart it.
|
|
||||||
unset($g_future);
|
|
||||||
sleep(2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue