Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/daemon/controller/PhabricatorDaemonConsoleController.php b/src/applications/daemon/controller/PhabricatorDaemonConsoleController.php
index 97242969b0..70eb3c78d3 100644
--- a/src/applications/daemon/controller/PhabricatorDaemonConsoleController.php
+++ b/src/applications/daemon/controller/PhabricatorDaemonConsoleController.php
@@ -1,231 +1,232 @@
<?php
final class PhabricatorDaemonConsoleController
extends PhabricatorDaemonController {
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$window_start = (time() - (60 * 15));
// Assume daemons spend about 250ms second in overhead per task acquiring
// leases and doing other bookkeeping. This is probably an over-estimation,
// but we'd rather show that utilization is too high than too low.
$lease_overhead = 0.250;
$completed = id(new PhabricatorWorkerArchiveTask())->loadAllWhere(
'dateModified > %d',
$window_start);
$failed = id(new PhabricatorWorkerActiveTask())->loadAllWhere(
'failureTime > %d',
$window_start);
$usage_total = 0;
$usage_start = PHP_INT_MAX;
$completed_info = array();
foreach ($completed as $completed_task) {
$class = $completed_task->getTaskClass();
if (empty($completed_info[$class])) {
$completed_info[$class] = array(
'n' => 0,
'duration' => 0,
);
}
$completed_info[$class]['n']++;
$duration = $completed_task->getDuration();
$completed_info[$class]['duration'] += $duration;
// NOTE: Duration is in microseconds, but we're just using seconds to
// compute utilization.
$usage_total += $lease_overhead + ($duration / 1000000);
$usage_start = min($usage_start, $completed_task->getDateModified());
}
$completed_info = isort($completed_info, 'n');
$rows = array();
foreach ($completed_info as $class => $info) {
$rows[] = array(
$class,
number_format($info['n']),
number_format((int)($info['duration'] / $info['n'])).' us',
);
}
if ($failed) {
// Add the time it takes to restart the daemons. This includes a guess
// about other overhead of 2X.
$usage_total += PhutilDaemonOverseer::RESTART_WAIT * count($failed) * 2;
foreach ($failed as $failed_task) {
$usage_start = min($usage_start, $failed_task->getFailureTime());
}
$rows[] = array(
phutil_tag('em', array(), pht('Temporary Failures')),
count($failed),
null,
);
}
$logs = id(new PhabricatorDaemonLogQuery())
->setViewer($user)
->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE)
+ ->setAllowStatusWrites(true)
->execute();
$taskmasters = 0;
foreach ($logs as $log) {
if ($log->getDaemon() == 'PhabricatorTaskmasterDaemon') {
$taskmasters++;
}
}
if ($taskmasters && $usage_total) {
// Total number of wall-time seconds the daemons have been running since
// the oldest event. For very short times round up to 15s so we don't
// render any ridiculous numbers if you reload the page immediately after
// restarting the daemons.
$available_time = $taskmasters * max(15, (time() - $usage_start));
// Percentage of those wall-time seconds we can account for, which the
// daemons spent doing work:
$used_time = ($usage_total / $available_time);
$rows[] = array(
phutil_tag('em', array(), pht('Queue Utilization (Approximate)')),
sprintf('%.1f%%', 100 * $used_time),
null,
);
}
$completed_table = new AphrontTableView($rows);
$completed_table->setNoDataString(
pht('No tasks have completed in the last 15 minutes.'));
$completed_table->setHeaders(
array(
pht('Class'),
pht('Count'),
pht('Avg'),
));
$completed_table->setColumnClasses(
array(
'wide',
'n',
'n',
));
$completed_panel = new PHUIObjectBoxView();
$completed_panel->setHeaderText(
pht('Recently Completed Tasks (Last 15m)'));
$completed_panel->appendChild($completed_table);
$daemon_table = new PhabricatorDaemonLogListView();
$daemon_table->setUser($user);
$daemon_table->setDaemonLogs($logs);
$tasks = id(new PhabricatorWorkerActiveTask())->loadAllWhere(
'leaseOwner IS NOT NULL');
$rows = array();
foreach ($tasks as $task) {
$rows[] = array(
$task->getID(),
$task->getTaskClass(),
$task->getLeaseOwner(),
$task->getLeaseExpires() - time(),
$task->getFailureCount(),
phutil_tag(
'a',
array(
'href' => '/daemon/task/'.$task->getID().'/',
'class' => 'button small grey',
),
pht('View Task')),
);
}
$daemon_panel = new PHUIObjectBoxView();
$daemon_panel->setHeaderText(pht('Active Daemons'));
$daemon_panel->appendChild($daemon_table);
$leased_table = new AphrontTableView($rows);
$leased_table->setHeaders(
array(
pht('ID'),
pht('Class'),
pht('Owner'),
pht('Expires'),
pht('Failures'),
'',
));
$leased_table->setColumnClasses(
array(
'n',
'wide',
'',
'',
'n',
'action',
));
$leased_table->setNoDataString(pht('No tasks are leased by workers.'));
$leased_panel = new PHUIObjectBoxView();
$leased_panel->setHeaderText(pht('Leased Tasks'));
$leased_panel->appendChild($leased_table);
$task_table = new PhabricatorWorkerActiveTask();
$queued = queryfx_all(
$task_table->establishConnection('r'),
'SELECT taskClass, count(*) N FROM %T GROUP BY taskClass
ORDER BY N DESC',
$task_table->getTableName());
$rows = array();
foreach ($queued as $row) {
$rows[] = array(
$row['taskClass'],
number_format($row['N']),
);
}
$queued_table = new AphrontTableView($rows);
$queued_table->setHeaders(
array(
pht('Class'),
pht('Count'),
));
$queued_table->setColumnClasses(
array(
'wide',
'n',
));
$queued_table->setNoDataString(pht('Task queue is empty.'));
$queued_panel = new PHUIObjectBoxView();
$queued_panel->setHeaderText(pht('Queued Tasks'));
$queued_panel->appendChild($queued_table);
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Console'));
$nav = $this->buildSideNavView();
$nav->selectFilter('/');
$nav->appendChild(
array(
$crumbs,
$completed_panel,
$daemon_panel,
$queued_panel,
$leased_panel,
));
return $this->buildApplicationPage(
$nav,
array(
'title' => pht('Console'),
));
}
}
diff --git a/src/applications/daemon/controller/PhabricatorDaemonLogListController.php b/src/applications/daemon/controller/PhabricatorDaemonLogListController.php
index e97220a243..0e5552dcf7 100644
--- a/src/applications/daemon/controller/PhabricatorDaemonLogListController.php
+++ b/src/applications/daemon/controller/PhabricatorDaemonLogListController.php
@@ -1,38 +1,39 @@
<?php
final class PhabricatorDaemonLogListController
extends PhabricatorDaemonController {
public function processRequest() {
$request = $this->getRequest();
$viewer = $request->getUser();
$pager = new AphrontCursorPagerView();
$pager->readFromRequest($request);
$logs = id(new PhabricatorDaemonLogQuery())
->setViewer($viewer)
+ ->setAllowStatusWrites(true)
->executeWithCursorPager($pager);
$daemon_table = new PhabricatorDaemonLogListView();
$daemon_table->setUser($request->getUser());
$daemon_table->setDaemonLogs($logs);
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('All Daemons'));
$nav = $this->buildSideNavView();
$nav->selectFilter('log');
$nav->setCrumbs($crumbs);
$nav->appendChild($daemon_table);
$nav->appendChild($pager);
return $this->buildApplicationPage(
$nav,
array(
'title' => pht('All Daemons'),
'device' => true,
));
}
}
diff --git a/src/applications/daemon/controller/PhabricatorDaemonLogViewController.php b/src/applications/daemon/controller/PhabricatorDaemonLogViewController.php
index 5116c46223..9da72ceb01 100644
--- a/src/applications/daemon/controller/PhabricatorDaemonLogViewController.php
+++ b/src/applications/daemon/controller/PhabricatorDaemonLogViewController.php
@@ -1,181 +1,182 @@
<?php
final class PhabricatorDaemonLogViewController
extends PhabricatorDaemonController {
private $id;
public function willProcessRequest(array $data) {
$this->id = $data['id'];
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$log = id(new PhabricatorDaemonLogQuery())
->setViewer($user)
->withIDs(array($this->id))
+ ->setAllowStatusWrites(true)
->executeOne();
if (!$log) {
return new Aphront404Response();
}
$events = id(new PhabricatorDaemonLogEvent())->loadAllWhere(
'logID = %d ORDER BY id DESC LIMIT 1000',
$log->getID());
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Daemon %s', $log->getID()));
$header = id(new PHUIHeaderView())
->setHeader($log->getDaemon());
$tag = id(new PHUITagView())
->setType(PHUITagView::TYPE_STATE);
$status = $log->getStatus();
switch ($status) {
case PhabricatorDaemonLog::STATUS_UNKNOWN:
$tag->setBackgroundColor(PHUITagView::COLOR_ORANGE);
$tag->setName(pht('Unknown'));
break;
case PhabricatorDaemonLog::STATUS_RUNNING:
$tag->setBackgroundColor(PHUITagView::COLOR_GREEN);
$tag->setName(pht('Running'));
break;
case PhabricatorDaemonLog::STATUS_DEAD:
$tag->setBackgroundColor(PHUITagView::COLOR_RED);
$tag->setName(pht('Dead'));
break;
case PhabricatorDaemonLog::STATUS_WAIT:
$tag->setBackgroundColor(PHUITagView::COLOR_BLUE);
$tag->setName(pht('Waiting'));
break;
case PhabricatorDaemonLog::STATUS_EXITED:
$tag->setBackgroundColor(PHUITagView::COLOR_GREY);
$tag->setName(pht('Exited'));
break;
}
$header->addTag($tag);
$properties = $this->buildPropertyListView($log);
$event_view = id(new PhabricatorDaemonLogEventsView())
->setUser($user)
->setEvents($events);
$event_panel = new AphrontPanelView();
$event_panel->setNoBackground();
$event_panel->appendChild($event_view);
$object_box = id(new PHUIObjectBoxView())
->setHeader($header)
->addPropertyList($properties);
return $this->buildApplicationPage(
array(
$crumbs,
$object_box,
$event_panel,
),
array(
'title' => pht('Daemon Log'),
));
}
private function buildPropertyListView(PhabricatorDaemonLog $daemon) {
$request = $this->getRequest();
$viewer = $request->getUser();
$view = id(new PHUIPropertyListView())
->setUser($viewer);
$id = $daemon->getID();
$c_epoch = $daemon->getDateCreated();
$u_epoch = $daemon->getDateModified();
$unknown_time = PhabricatorDaemonLogQuery::getTimeUntilUnknown();
$dead_time = PhabricatorDaemonLogQuery::getTimeUntilDead();
$wait_time = PhutilDaemonOverseer::RESTART_WAIT;
$details = null;
$status = $daemon->getStatus();
switch ($status) {
case PhabricatorDaemonLog::STATUS_RUNNING:
$details = pht(
'This daemon is running normally and reported a status update '.
'recently (within %s).',
phabricator_format_relative_time($unknown_time));
break;
case PhabricatorDaemonLog::STATUS_UNKNOWN:
$details = pht(
'This daemon has not reported a status update recently (within %s). '.
'It may have exited abruptly. After %s, it will be presumed dead.',
phabricator_format_relative_time($unknown_time),
phabricator_format_relative_time($dead_time));
break;
case PhabricatorDaemonLog::STATUS_DEAD:
$details = pht(
'This daemon did not report a status update for %s. It is '.
'presumed dead. Usually, this indicates that the daemon was '.
'killed or otherwise exited abruptly with an error. You may '.
'need to restart it.',
phabricator_format_relative_time($dead_time));
break;
case PhabricatorDaemonLog::STATUS_WAIT:
$details = pht(
'This daemon is running normally and reported a status update '.
'recently (within %s). However, it encountered an error while '.
'doing work and is waiting a little while (%s) to resume '.
'processing. After encountering an error, daemons wait before '.
'resuming work to avoid overloading services.',
phabricator_format_relative_time($unknown_time),
phabricator_format_relative_time($wait_time));
break;
case PhabricatorDaemonLog::STATUS_EXITED:
$details = pht(
'This daemon exited normally and is no longer running.');
break;
}
$view->addProperty(pht('Status Details'), $details);
$view->addProperty(pht('Daemon Class'), $daemon->getDaemon());
$view->addProperty(pht('Host'), $daemon->getHost());
$view->addProperty(pht('PID'), $daemon->getPID());
$view->addProperty(pht('Started'), phabricator_datetime($c_epoch, $viewer));
$view->addProperty(
pht('Seen'),
pht(
'%s ago (%s)',
phabricator_format_relative_time(time() - $u_epoch),
phabricator_datetime($u_epoch, $viewer)));
$argv = $daemon->getArgv();
if (is_array($argv)) {
$argv = implode("\n", $argv);
}
$view->addProperty(
pht('Argv'),
phutil_tag(
'textarea',
array(
'style' => 'width: 100%; height: 12em;',
),
$argv));
$view->addProperty(
pht('View Full Logs'),
phutil_tag(
'tt',
array(),
"phabricator/ $ ./bin/phd log {$id}"));
return $view;
}
}
diff --git a/src/applications/daemon/management/PhabricatorDaemonManagementLogWorkflow.php b/src/applications/daemon/management/PhabricatorDaemonManagementLogWorkflow.php
index 8613ef6de4..4c65c74e8f 100644
--- a/src/applications/daemon/management/PhabricatorDaemonManagementLogWorkflow.php
+++ b/src/applications/daemon/management/PhabricatorDaemonManagementLogWorkflow.php
@@ -1,79 +1,80 @@
<?php
final class PhabricatorDaemonManagementLogWorkflow
extends PhabricatorDaemonManagementWorkflow {
public function didConstruct() {
$this
->setName('log')
->setExamples('**log** __id__')
->setSynopsis(
pht(
'Print the log for a daemon, identified by ID. You can get the '.
'ID for a daemon from the Daemon Console in the web interface.'))
->setArguments(
array(
array(
'name' => 'daemon',
'wildcard' => true,
),
));
}
public function execute(PhutilArgumentParser $args) {
$id = $args->getArg('daemon');
if (!$id) {
throw new PhutilArgumentUsageException(
pht('You must specify the daemon ID to show logs for.'));
} else if (count($id) > 1) {
throw new PhutilArgumentUsageException(
pht('Specify exactly one daemon ID to show logs for.'));
}
$id = head($id);
$daemon = id(new PhabricatorDaemonLogQuery())
->setViewer($this->getViewer())
->withIDs(array($id))
+ ->setAllowStatusWrites(true)
->executeOne();
if (!$daemon) {
throw new PhutilArgumentUsageException(
pht('No such daemon with id "%s"!', $id));
}
$console = PhutilConsole::getConsole();
$logs = id(new PhabricatorDaemonLogEvent())->loadAllWhere(
'logID = %d ORDER BY id ASC',
$daemon->getID());
$lines = array();
foreach ($logs as $log) {
$text_lines = phutil_split_lines($log->getMessage(), $retain = false);
foreach ($text_lines as $line) {
$lines[] = array(
'type' => $log->getLogType(),
'date' => $log->getEpoch(),
'data' => $line,
);
}
}
foreach ($lines as $line) {
$type = $line['type'];
$data = $line['data'];
$date = date('r', $line['date']);
$console->writeOut(
"%s\n",
sprintf(
'[%s] %s %s',
$date,
$type,
$data));
}
return 0;
}
}
diff --git a/src/applications/daemon/query/PhabricatorDaemonLogQuery.php b/src/applications/daemon/query/PhabricatorDaemonLogQuery.php
index 656edd7bdc..c3f2ddf7f0 100644
--- a/src/applications/daemon/query/PhabricatorDaemonLogQuery.php
+++ b/src/applications/daemon/query/PhabricatorDaemonLogQuery.php
@@ -1,149 +1,160 @@
<?php
final class PhabricatorDaemonLogQuery
extends PhabricatorCursorPagedPolicyAwareQuery {
const STATUS_ALL = 'status-all';
const STATUS_ALIVE = 'status-alive';
private $ids;
private $status = self::STATUS_ALL;
private $daemonClasses;
+ private $allowStatusWrites;
public static function getTimeUntilUnknown() {
return 3 * PhutilDaemonOverseer::HEARTBEAT_WAIT;
}
public static function getTimeUntilDead() {
return 30 * PhutilDaemonOverseer::HEARTBEAT_WAIT;
}
public function withIDs(array $ids) {
$this->ids = $ids;
return $this;
}
public function withStatus($status) {
$this->status = $status;
return $this;
}
public function withDaemonClasses(array $classes) {
$this->daemonClasses = $classes;
return $this;
}
+ public function setAllowStatusWrites($allow) {
+ $this->allowStatusWrites = $allow;
+ return $this;
+ }
+
public function loadPage() {
$table = new PhabricatorDaemonLog();
$conn_r = $table->establishConnection('r');
$data = queryfx_all(
$conn_r,
'SELECT * FROM %T %Q %Q %Q',
$table->getTableName(),
$this->buildWhereClause($conn_r),
$this->buildOrderClause($conn_r),
$this->buildLimitClause($conn_r));
return $table->loadAllFromArray($data);
}
public function willFilterPage(array $daemons) {
$unknown_delay = PhabricatorDaemonLogQuery::getTimeUntilUnknown();
$dead_delay = PhabricatorDaemonLogQuery::getTimeUntilDead();
$status_running = PhabricatorDaemonLog::STATUS_RUNNING;
$status_unknown = PhabricatorDaemonLog::STATUS_UNKNOWN;
$status_wait = PhabricatorDaemonLog::STATUS_WAIT;
$status_exited = PhabricatorDaemonLog::STATUS_EXITED;
$status_dead = PhabricatorDaemonLog::STATUS_DEAD;
$filter = array_fuse($this->getStatusConstants());
foreach ($daemons as $key => $daemon) {
$status = $daemon->getStatus();
$seen = $daemon->getDateModified();
$is_running = ($status == $status_running) ||
($status == $status_wait);
// If we haven't seen the daemon recently, downgrade its status to
// unknown.
$unknown_time = ($seen + $unknown_delay);
if ($is_running && ($unknown_time < time())) {
$status = $status_unknown;
}
// If the daemon hasn't been seen in quite a while, assume it is dead.
$dead_time = ($seen + $dead_delay);
if (($status == $status_unknown) && ($dead_time < time())) {
$status = $status_dead;
}
- // If we changed the daemon's status, update it.
+ // If we changed the daemon's status, adjust it.
if ($status != $daemon->getStatus()) {
- $guard = AphrontWriteGuard::beginScopedUnguardedWrites();
- $daemon->setStatus($status)->save();
- unset($guard);
+ $daemon->setStatus($status);
+
+ // ...and write it, if we're in a context where that's reasonable.
+ if ($this->allowStatusWrites) {
+ $guard = AphrontWriteGuard::beginScopedUnguardedWrites();
+ $daemon->save();
+ unset($guard);
+ }
}
// If the daemon no longer matches the filter, get rid of it.
if ($filter) {
if (empty($filter[$daemon->getStatus()])) {
unset($daemons[$key]);
}
}
}
return $daemons;
}
private function buildWhereClause(AphrontDatabaseConnection $conn_r) {
$where = array();
if ($this->ids) {
$where[] = qsprintf(
$conn_r,
'id IN (%Ld)',
$this->ids);
}
if ($this->getStatusConstants()) {
$where[] = qsprintf(
$conn_r,
'status IN (%Ls)',
$this->getStatusConstants());
}
if ($this->daemonClasses) {
$where[] = qsprintf(
$conn_r,
'daemon IN (%Ls)',
$this->daemonClasses);
}
$where[] = $this->buildPagingClause($conn_r);
return $this->formatWhereClause($where);
}
private function getStatusConstants() {
$status = $this->status;
switch ($status) {
case self::STATUS_ALL:
return array();
case self::STATUS_ALIVE:
return array(
PhabricatorDaemonLog::STATUS_UNKNOWN,
PhabricatorDaemonLog::STATUS_RUNNING,
PhabricatorDaemonLog::STATUS_WAIT,
);
default:
throw new Exception("Unknown status '{$status}'!");
}
}
public function getQueryApplicationClass() {
return 'PhabricatorApplicationDaemons';
}
}

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jul 29, 6:05 AM (2 w, 5 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
188108
Default Alt Text
(21 KB)

Event Timeline