Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15467193
D9226.id22105.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
16 KB
Referenced Files
None
Subscribers
None
D9226.id22105.diff
View Options
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1102,6 +1102,12 @@
'PhabricatorActionView' => 'view/layout/PhabricatorActionView.php',
'PhabricatorAllCapsTranslation' => 'infrastructure/internationalization/translation/PhabricatorAllCapsTranslation.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',
'PhabricatorAphrontViewTestCase' => 'view/__tests__/PhabricatorAphrontViewTestCase.php',
'PhabricatorAppSearchEngine' => 'applications/meta/query/PhabricatorAppSearchEngine.php',
@@ -3848,6 +3854,12 @@
'PhabricatorActionView' => 'AphrontView',
'PhabricatorAllCapsTranslation' => 'PhabricatorTranslation',
'PhabricatorAnchorView' => 'AphrontView',
+ 'PhabricatorAphlictManagementDebugWorkflow' => 'PhabricatorAphlictManagementWorkflow',
+ 'PhabricatorAphlictManagementRestartWorkflow' => 'PhabricatorAphlictManagementWorkflow',
+ 'PhabricatorAphlictManagementStartWorkflow' => 'PhabricatorAphlictManagementWorkflow',
+ 'PhabricatorAphlictManagementStatusWorkflow' => 'PhabricatorAphlictManagementWorkflow',
+ 'PhabricatorAphlictManagementStopWorkflow' => 'PhabricatorAphlictManagementWorkflow',
+ 'PhabricatorAphlictManagementWorkflow' => 'PhabricatorManagementWorkflow',
'PhabricatorAphrontBarExample' => 'PhabricatorUIExample',
'PhabricatorAphrontViewTestCase' => 'PhabricatorTestCase',
'PhabricatorAppSearchEngine' => 'PhabricatorApplicationSearchEngine',
diff --git a/src/applications/aphlict/management/PhabricatorAphlictManagementDebugWorkflow.php b/src/applications/aphlict/management/PhabricatorAphlictManagementDebugWorkflow.php
new file mode 100644
--- /dev/null
+++ b/src/applications/aphlict/management/PhabricatorAphlictManagementDebugWorkflow.php
@@ -0,0 +1,20 @@
+<?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) {
+ return $this->launch(true);
+ }
+
+}
diff --git a/src/applications/aphlict/management/PhabricatorAphlictManagementRestartWorkflow.php b/src/applications/aphlict/management/PhabricatorAphlictManagementRestartWorkflow.php
new file mode 100644
--- /dev/null
+++ b/src/applications/aphlict/management/PhabricatorAphlictManagementRestartWorkflow.php
@@ -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();
+ }
+
+}
diff --git a/src/applications/aphlict/management/PhabricatorAphlictManagementStartWorkflow.php b/src/applications/aphlict/management/PhabricatorAphlictManagementStartWorkflow.php
new file mode 100644
--- /dev/null
+++ b/src/applications/aphlict/management/PhabricatorAphlictManagementStartWorkflow.php
@@ -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();
+ }
+
+}
diff --git a/src/applications/aphlict/management/PhabricatorAphlictManagementStatusWorkflow.php b/src/applications/aphlict/management/PhabricatorAphlictManagementStatusWorkflow.php
new file mode 100644
--- /dev/null
+++ b/src/applications/aphlict/management/PhabricatorAphlictManagementStatusWorkflow.php
@@ -0,0 +1,27 @@
+<?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;
+ }
+
+
+}
diff --git a/src/applications/aphlict/management/PhabricatorAphlictManagementStopWorkflow.php b/src/applications/aphlict/management/PhabricatorAphlictManagementStopWorkflow.php
new file mode 100644
--- /dev/null
+++ b/src/applications/aphlict/management/PhabricatorAphlictManagementStopWorkflow.php
@@ -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();
+ }
+
+}
diff --git a/src/applications/aphlict/management/PhabricatorAphlictManagementWorkflow.php b/src/applications/aphlict/management/PhabricatorAphlictManagementWorkflow.php
new file mode 100644
--- /dev/null
+++ b/src/applications/aphlict/management/PhabricatorAphlictManagementWorkflow.php
@@ -0,0 +1,170 @@
+<?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;
+ }
+
+ public function cleanup($signo) {
+ Filesystem::remove($this->getPIDPath());
+
+ }
+
+ 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);
+ }
+ }
+ }
+
+ protected function launch($debug = false) {
+ $console = PhutilConsole::getConsole();
+
+ $pid = $this->getPID();
+ if ($pid) {
+ $console->writeErr(
+ 'aphlict start: Unable to start notifications server because it is '.
+ 'already running.');
+ exit(1);
+ }
+
+ if (posix_getuid() != 0) {
+ $console->writeErr(
+ 'You must run this script as root; the Aphlict server needs to bind '.
+ 'to privileged ports.');
+ exit(1);
+ }
+
+ list($err) = exec_manual('node -v');
+ if ($err) {
+ $console->writeErr(
+ '`node` is not in $PATH. You must install Node.js to run the Aphlict '.
+ 'server.');
+ exit(1);
+ }
+
+ if ($debug) {
+ $console->writeOut(pht("Starting 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(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) {
+ id(new ExecFuture('exec %C', $command))->resolve();
+
+ // If the server exited, wait a couple of seconds and restart it.
+ sleep(2);
+ }
+ }
+ }
+
+
+/* -( Commands )----------------------------------------------------------- */
+
+
+ protected function executeStartCommand() {
+ $console = PhutilConsole::getConsole();
+
+ $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);
+
+ $this->launch();
+ $console->writeErr(pht("Done.\n"));
+ return 0;
+ }
+
+
+ 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 (%s)...\n", $pid));
+ posix_kill($pid, SIGKILL);
+
+ return 0;
+ }
+
+}
diff --git a/support/aphlict/server/aphlict_launcher.php b/support/aphlict/server/aphlict_launcher.php
--- a/support/aphlict/server/aphlict_launcher.php
+++ b/support/aphlict/server/aphlict_launcher.php
@@ -1,164 +1,25 @@
#!/usr/bin/env 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__))));
require_once $root.'/scripts/__init_script__.php';
-
-// >>> Options and Arguments ---------------------------------------------------
+PhabricatorAphlictManagementWorkflow::requireExtensions();
$args = new PhutilArgumentParser($argv);
$args->setTagline('manage Aphlict notification server');
$args->setSynopsis(<<<EOHELP
-**aphlict** [__options__]
- Start (or restart) the Aphlict server.
+**aphlict** __command__ [__options__]
+ Manage the Aphlict server.
EOHELP
);
$args->parseStandardArguments();
-$args->parse(array(
- array(
- 'name' => 'foreground',
- 'help' => 'Run in the foreground instead of daemonizing.',
- ),
-));
-
-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);
- }
-}
+$args->parseWorkflows(array(
+ new PhabricatorAphlictManagementStatusWorkflow(),
+ new PhabricatorAphlictManagementStartWorkflow(),
+ new PhabricatorAphlictManagementStopWorkflow(),
+ new PhabricatorAphlictManagementRestartWorkflow(),
+ new PhabricatorAphlictManagementDebugWorkflow(),
+ new PhutilHelpArgumentWorkflow(),
+));
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Apr 4, 1:37 PM (1 w, 3 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7623582
Default Alt Text
D9226.id22105.diff (16 KB)
Attached To
Mode
D9226: Make `./bin/aphlict` behave more like a service.
Attached
Detach File
Event Timeline
Log In to Comment