@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Save daemon state to database

Summary:
To make it easier to monitor daemons, let's store their current state
(running, died, exited, or unknown) to the db. The purpose of this is to
provide more information on the daemon console about the status of daemons,
especially when they are running on multiple machines. This is mostly backend
work, with only a few frontend changes. (It is also dependent on a change
to libphutil.)

These changes will make dead or stuck daemons more obvious, and will allow
more work on the frontend to hide daemons (and logs) that have exited cleanly,
i.e. ones we don't care about any more.

Test Plan:
- run db migration, check in db that all daemons were marked as exited
- start up a daemon, check in db that it is marked as running
- open web interface, check that daemon is listed as running
- after daemon has been running for a little bit, check in db that dateModified
is being updated (indicating daemon is properly sending heartbeat)
- kill -9 daemon (but don't run bin/phd yet), and check that db still shows it
as running
- edit daemon db entry to show it as being on a different host, and backdate
dateModified field by 3 minutes, and check the web ui to show that the status
is unknown.
- change db entry to have proper host, check in web ui that daemon status is
displayed as dead. Check db to see that the status was saved.
- run bin/phd stop, and see that the formerly dead daemon is now exited.

Reviewers: epriestley, vrana

Reviewed By: epriestley

CC: aran, Korvin

Differential Revision: https://secure.phabricator.com/D3126

+155 -26
+4
resources/sql/patches/daemonstatus.sql
··· 1 + ALTER TABLE {$NAMESPACE}_daemon.daemon_log 2 + ADD COLUMN `status` varchar(8) NOT NULL; 3 + 4 + UPDATE {$NAMESPACE}_daemon.daemon_log SET `status`='exit';
+2
src/__phutil_library_map__.php
··· 112 112 'ConduitAPI_conduit_ping_Method' => 'applications/conduit/method/conduit/ConduitAPI_conduit_ping_Method.php', 113 113 'ConduitAPI_daemon_launched_Method' => 'applications/conduit/method/daemon/ConduitAPI_daemon_launched_Method.php', 114 114 'ConduitAPI_daemon_log_Method' => 'applications/conduit/method/daemon/ConduitAPI_daemon_log_Method.php', 115 + 'ConduitAPI_daemon_setstatus_Method' => 'applications/conduit/method/daemon/ConduitAPI_daemon_setstatus_Method.php', 115 116 'ConduitAPI_differential_Method' => 'applications/conduit/method/differential/ConduitAPI_differential_Method.php', 116 117 'ConduitAPI_differential_close_Method' => 'applications/conduit/method/differential/ConduitAPI_differential_close_Method.php', 117 118 'ConduitAPI_differential_createcomment_Method' => 'applications/conduit/method/differential/ConduitAPI_differential_createcomment_Method.php', ··· 1229 1230 'ConduitAPI_conduit_ping_Method' => 'ConduitAPIMethod', 1230 1231 'ConduitAPI_daemon_launched_Method' => 'ConduitAPIMethod', 1231 1232 'ConduitAPI_daemon_log_Method' => 'ConduitAPIMethod', 1233 + 'ConduitAPI_daemon_setstatus_Method' => 'ConduitAPIMethod', 1232 1234 'ConduitAPI_differential_Method' => 'ConduitAPIMethod', 1233 1235 'ConduitAPI_differential_close_Method' => 'ConduitAPIMethod', 1234 1236 'ConduitAPI_differential_createcomment_Method' => 'ConduitAPIMethod',
+1
src/applications/conduit/method/daemon/ConduitAPI_daemon_launched_Method.php
··· 58 58 $daemon_log->setDaemon($request->getValue('daemon')); 59 59 $daemon_log->setHost($request->getValue('host')); 60 60 $daemon_log->setPID($request->getValue('pid')); 61 + $daemon_log->setStatus(PhabricatorDaemonLog::STATUS_RUNNING); 61 62 $daemon_log->setArgv(json_decode($request->getValue('argv'))); 62 63 63 64 $daemon_log->save();
+66
src/applications/conduit/method/daemon/ConduitAPI_daemon_setstatus_Method.php
··· 1 + <?php 2 + 3 + /* 4 + * Copyright 2012 Facebook, Inc. 5 + * 6 + * Licensed under the Apache License, Version 2.0 (the "License"); 7 + * you may not use this file except in compliance with the License. 8 + * You may obtain a copy of the License at 9 + * 10 + * http://www.apache.org/licenses/LICENSE-2.0 11 + * 12 + * Unless required by applicable law or agreed to in writing, software 13 + * distributed under the License is distributed on an "AS IS" BASIS, 14 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 + * See the License for the specific language governing permissions and 16 + * limitations under the License. 17 + */ 18 + 19 + /** 20 + * @group conduit 21 + */ 22 + final class ConduitAPI_daemon_setstatus_Method extends ConduitAPIMethod { 23 + 24 + public function shouldRequireAuthentication() { 25 + // TODO: Lock this down once we build phantoms. 26 + return false; 27 + } 28 + 29 + public function shouldAllowUnguardedWrites() { 30 + return true; 31 + } 32 + 33 + public function getMethodDescription() { 34 + return "Used by daemons to update their status."; 35 + } 36 + 37 + public function defineParamTypes() { 38 + return array( 39 + 'daemonLogID' => 'required string', 40 + 'status' => 'required enum<unknown, run, timeout, dead, exit>', 41 + ); 42 + } 43 + 44 + public function defineReturnType() { 45 + return 'void'; 46 + } 47 + 48 + public function defineErrorTypes() { 49 + return array( 50 + 'ERR-INVALID-ID' => 'An invalid daemonLogID was provided.', 51 + ); 52 + } 53 + 54 + protected function execute(ConduitAPIRequest $request) { 55 + 56 + $daemon_log = id(new PhabricatorDaemonLog()) 57 + ->load($request->getValue('daemonLogID')); 58 + if (!$daemon_log) { 59 + throw new ConduitException('ERR-INVALID-ID'); 60 + } 61 + $daemon_log->setStatus($request->getValue('status')); 62 + 63 + $daemon_log->save(); 64 + } 65 + 66 + }
+48 -26
src/applications/daemon/view/PhabricatorDaemonLogListView.php
··· 42 42 foreach ($this->daemonLogs as $log) { 43 43 $epoch = $log->getDateCreated(); 44 44 45 - if ($log->getHost() == php_uname('n')) { 45 + $status = $log->getStatus(); 46 + if ($log->getHost() == php_uname('n') && 47 + $status != PhabricatorDaemonLog::STATUS_EXITED && 48 + $status != PhabricatorDaemonLog::STATUS_DEAD) { 46 49 47 50 $pid = $log->getPID(); 48 51 $is_running = PhabricatorDaemonReference::isProcessRunning($pid); 49 - 50 - if ($is_running) { 51 - $running = phutil_render_tag( 52 - 'span', 53 - array( 54 - 'style' => 'color: #00cc00', 55 - 'title' => 'Running', 56 - ), 57 - '&bull;'); 58 - } else { 59 - $running = phutil_render_tag( 60 - 'span', 61 - array( 62 - 'style' => 'color: #cc0000', 63 - 'title' => 'Not running', 64 - ), 65 - '&bull;'); 52 + if (!$is_running) { 53 + $guard = AphrontWriteGuard::beginScopedUnguardedWrites(); 54 + $log->setStatus(PhabricatorDaemonLog::STATUS_DEAD); 55 + $log->save(); 56 + unset($guard); 57 + $status = PhabricatorDaemonLog::STATUS_DEAD; 66 58 } 67 - } else { 68 - $running = phutil_render_tag( 69 - 'span', 70 - array( 71 - 'style' => 'color: #888888', 72 - 'title' => 'Not on this host', 73 - ), 74 - '?'); 75 59 } 60 + 61 + $heartbeat_timeout = 62 + $log->getDateModified() + 3 * PhutilDaemonOverseer::HEARTBEAT_WAIT; 63 + if ($status == PhabricatorDaemonLog::STATUS_RUNNING && 64 + $heartbeat_timeout < time()) { 65 + $status = PhabricatorDaemonLog::STATUS_UNKNOWN; 66 + } 67 + 68 + switch ($status) { 69 + case PhabricatorDaemonLog::STATUS_RUNNING: 70 + $style = 'color: #00cc00'; 71 + $title = 'Running'; 72 + $symbol = '&bull;'; 73 + break; 74 + case PhabricatorDaemonLog::STATUS_DEAD: 75 + $style = 'color: #cc0000'; 76 + $title = 'Died'; 77 + $symbol = '&bull;'; 78 + break; 79 + case PhabricatorDaemonLog::STATUS_EXITED: 80 + $style = 'color: #000000'; 81 + $title = 'Exited'; 82 + $symbol = '&bull;'; 83 + break; 84 + case PhabricatorDaemonLog::STATUS_UNKNOWN: 85 + default: // fallthrough 86 + $style = 'color: #888888'; 87 + $title = 'Unknown'; 88 + $symbol = '?'; 89 + } 90 + 91 + $running = phutil_render_tag( 92 + 'span', 93 + array( 94 + 'style' => $style, 95 + 'title' => $title, 96 + ), 97 + $symbol); 76 98 77 99 $rows[] = array( 78 100 $running,
+11
src/infrastructure/daemon/PhabricatorDaemonControl.php
··· 53 53 foreach ($daemons as $daemon) { 54 54 $name = $daemon->getName(); 55 55 if (!$daemon->isRunning()) { 56 + $daemon_log = $daemon->loadDaemonLog(); 57 + if ($daemon_log) { 58 + $daemon_log->setStatus(PhabricatorDaemonLog::STATUS_DEAD); 59 + $daemon_log->save(); 60 + } 61 + 56 62 $status = 2; 57 63 $name = '<DEAD> '.$name; 58 64 } ··· 110 116 if (!$daemon->isRunning()) { 111 117 echo "Daemon is not running.\n"; 112 118 unset($running[$key]); 119 + $daemon_log = $daemon->loadDaemonLog(); 120 + if ($daemon_log) { 121 + $daemon_log->setStatus(PhabricatorDaemonLog::STATUS_EXITED); 122 + $daemon_log->save(); 123 + } 113 124 } else { 114 125 posix_kill($pid, SIGINT); 115 126 }
+13
src/infrastructure/daemon/control/PhabricatorDaemonReference.php
··· 23 23 private $start; 24 24 private $pidFile; 25 25 26 + private $daemonLog; 27 + 26 28 public static function newFromDictionary(array $dict) { 27 29 $ref = new PhabricatorDaemonReference(); 28 30 ··· 31 33 $ref->start = idx($dict, 'start'); 32 34 33 35 return $ref; 36 + } 37 + 38 + public function loadDaemonLog() { 39 + if (!$this->daemonLog) { 40 + $this->daemonLog = id(new PhabricatorDaemonLog())->loadOneWhere( 41 + 'daemon = %s AND pid = %d AND dateCreated = %d', 42 + $this->name, 43 + $this->pid, 44 + $this->start); 45 + } 46 + return $this->daemonLog; 34 47 } 35 48 36 49 public function getPID() {
+6
src/infrastructure/daemon/storage/PhabricatorDaemonLog.php
··· 18 18 19 19 final class PhabricatorDaemonLog extends PhabricatorDaemonDAO { 20 20 21 + const STATUS_UNKNOWN = 'unknown'; 22 + const STATUS_RUNNING = 'run'; 23 + const STATUS_DEAD = 'dead'; 24 + const STATUS_EXITED = 'exit'; 25 + 21 26 protected $daemon; 22 27 protected $host; 23 28 protected $pid; 24 29 protected $argv; 30 + protected $status; 25 31 26 32 public function getConfiguration() { 27 33 return array(
+4
src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
··· 932 932 'type' => 'php', 933 933 'name' => $this->getPatchPath('migrate-maniphest-revisions.php'), 934 934 ), 935 + 'daemonstatus.sql' => array( 936 + 'type' => 'sql', 937 + 'name' => $this->getPatchPath('daemonstatus.sql'), 938 + ), 935 939 ); 936 940 } 937 941