diff --git a/src/applications/daemon/controller/PhabricatorDaemonBulkJobViewController.php b/src/applications/daemon/controller/PhabricatorDaemonBulkJobViewController.php index f32892cf4c..f78bfdd7df 100644 --- a/src/applications/daemon/controller/PhabricatorDaemonBulkJobViewController.php +++ b/src/applications/daemon/controller/PhabricatorDaemonBulkJobViewController.php @@ -1,89 +1,94 @@ getViewer(); $job = id(new PhabricatorWorkerBulkJobQuery()) ->setViewer($viewer) ->withIDs(array($request->getURIData('id'))) ->executeOne(); if (!$job) { return new Aphront404Response(); } $title = pht('Bulk Job %d', $job->getID()); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Bulk Jobs'), '/daemon/bulk/'); $crumbs->addTextCrumb($title); + $crumbs->setBorder(true); $properties = $this->renderProperties($job); - $actions = $this->renderActions($job); - $properties->setActionList($actions); + $curtain = $this->buildCurtainView($job); $box = id(new PHUIObjectBoxView()) - ->setHeaderText($title) + ->setHeaderText(pht('DETAILS')) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->addPropertyList($properties); $timeline = $this->buildTransactionTimeline( $job, new PhabricatorWorkerBulkJobTransactionQuery()); $timeline->setShouldTerminate(true); - return $this->buildApplicationPage( - array( - $crumbs, + $header = id(new PHUIHeaderView()) + ->setHeader($title) + ->setHeaderIcon('fa-hourglass'); + + $view = id(new PHUITwoColumnView()) + ->setHeader($header) + ->setCurtain($curtain) + ->setMainColumn(array( $box, $timeline, - ), - array( - 'title' => $title, )); + + return $this->newPage() + ->setTitle($title) + ->setCrumbs($crumbs) + ->appendChild($view); } private function renderProperties(PhabricatorWorkerBulkJob $job) { $viewer = $this->getViewer(); $view = id(new PHUIPropertyListView()) ->setUser($viewer) ->setObject($job); $view->addProperty( pht('Author'), $viewer->renderHandle($job->getAuthorPHID())); $view->addProperty(pht('Status'), $job->getStatusName()); return $view; } - private function renderActions(PhabricatorWorkerBulkJob $job) { + private function buildCurtainView(PhabricatorWorkerBulkJob $job) { $viewer = $this->getViewer(); - - $actions = id(new PhabricatorActionListView()) - ->setUser($viewer) - ->setObject($job); + $curtain = $this->newCurtainView($job); if ($job->isConfirming()) { $continue_uri = $job->getMonitorURI(); } else { $continue_uri = $job->getDoneURI(); } - $actions->addAction( + $curtain->addAction( id(new PhabricatorActionView()) ->setHref($continue_uri) ->setIcon('fa-arrow-circle-o-right') ->setName(pht('Continue'))); - return $actions; + return $curtain; } } diff --git a/src/applications/daemon/controller/PhabricatorDaemonConsoleController.php b/src/applications/daemon/controller/PhabricatorDaemonConsoleController.php index 9f54726bc9..a488ae3a63 100644 --- a/src/applications/daemon/controller/PhabricatorDaemonConsoleController.php +++ b/src/applications/daemon/controller/PhabricatorDaemonConsoleController.php @@ -1,271 +1,269 @@ getViewer(); $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 PhabricatorWorkerArchiveTaskQuery()) ->withDateModifiedSince($window_start) ->execute(); $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']), pht('%s us', new PhutilNumber((int)($info['duration'] / $info['n']))), ); } if ($failed) { // Add the time it takes to restart the daemons. This includes a guess // about other overhead of 2X. $restart_delay = PhutilDaemonHandle::getWaitBeforeRestart(); $usage_total += $restart_delay * 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($viewer) ->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->setTable($completed_table); + $completed_panel = id(new PHUIObjectBoxView()) + ->setHeaderText(pht('Recently Completed Tasks (Last 15m)')) + ->setTable($completed_table); $daemon_table = new PhabricatorDaemonLogListView(); $daemon_table->setUser($viewer); $daemon_table->setDaemonLogs($logs); - $daemon_panel = new PHUIObjectBoxView(); + $daemon_panel = id(new PHUIObjectBoxView()); $daemon_panel->setHeaderText(pht('Active Daemons')); $daemon_panel->setObjectList($daemon_table); $tasks = id(new PhabricatorWorkerLeaseQuery()) ->setSkipLease(true) ->withLeasedTasks(true) ->setLimit(100) ->execute(); $tasks_table = id(new PhabricatorDaemonTasksTableView()) ->setTasks($tasks) ->setNoDataString(pht('No tasks are leased by workers.')); $leased_panel = id(new PHUIObjectBoxView()) ->setHeaderText(pht('Leased Tasks')) ->setTable($tasks_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->setTable($queued_table); $upcoming = id(new PhabricatorWorkerLeaseQuery()) ->setLimit(10) ->setSkipLease(true) ->execute(); $upcoming_panel = id(new PHUIObjectBoxView()) ->setHeaderText(pht('Next In Queue')) ->setTable( id(new PhabricatorDaemonTasksTableView()) ->setTasks($upcoming) ->setNoDataString(pht('Task queue is empty.'))); $triggers = id(new PhabricatorWorkerTriggerQuery()) ->setViewer($viewer) ->setOrder(PhabricatorWorkerTriggerQuery::ORDER_EXECUTION) ->needEvents(true) ->setLimit(10) ->execute(); $triggers_table = $this->buildTriggersTable($triggers); $triggers_panel = id(new PHUIObjectBoxView()) ->setHeaderText(pht('Upcoming Triggers')) ->setTable($triggers_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, $upcoming_panel, $triggers_panel, )); - return $this->buildApplicationPage( - $nav, - array( - 'title' => pht('Console'), - )); + return $this->newPage() + ->setTitle(pht('Console')) + ->appendChild($nav); + } private function buildTriggersTable(array $triggers) { $viewer = $this->getViewer(); $rows = array(); foreach ($triggers as $trigger) { $event = $trigger->getEvent(); if ($event) { $last_epoch = $event->getLastEventEpoch(); $next_epoch = $event->getNextEventEpoch(); } else { $last_epoch = null; $next_epoch = null; } $rows[] = array( $trigger->getID(), $trigger->getClockClass(), $trigger->getActionClass(), $last_epoch ? phabricator_datetime($last_epoch, $viewer) : null, $next_epoch ? phabricator_datetime($next_epoch, $viewer) : null, ); } return id(new AphrontTableView($rows)) ->setNoDataString(pht('There are no upcoming event triggers.')) ->setHeaders( array( pht('ID'), pht('Clock'), pht('Action'), pht('Last'), pht('Next'), )) ->setColumnClasses( array( '', '', 'wide', 'date', 'date', )); } } diff --git a/src/applications/daemon/controller/PhabricatorDaemonLogEventViewController.php b/src/applications/daemon/controller/PhabricatorDaemonLogEventViewController.php index 772ee87fd1..208a20b9a0 100644 --- a/src/applications/daemon/controller/PhabricatorDaemonLogEventViewController.php +++ b/src/applications/daemon/controller/PhabricatorDaemonLogEventViewController.php @@ -1,43 +1,47 @@ getURIData('id'); $event = id(new PhabricatorDaemonLogEvent())->load($id); if (!$event) { return new Aphront404Response(); } $event_view = id(new PhabricatorDaemonLogEventsView()) ->setEvents(array($event)) ->setUser($request->getUser()) ->setCombinedLog(true) ->setShowFullMessage(true); - $log_panel = new PHUIObjectBoxView(); - $log_panel->setHeaderText(pht('Combined Log')); - $log_panel->appendChild($event_view); + $log_panel = id(new PHUIObjectBoxView()) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->appendChild($event_view); $daemon_id = $event->getLogID(); $crumbs = $this->buildApplicationCrumbs() ->addTextCrumb( pht('Daemon %s', $daemon_id), $this->getApplicationURI("log/{$daemon_id}/")) - ->addTextCrumb(pht('Event %s', $event->getID())); + ->addTextCrumb(pht('Event %s', $event->getID())) + ->setBorder(true); + $header = id(new PHUIHeaderView()) + ->setHeader(pht('Combined Log')) + ->setHeaderIcon('fa-file-text'); + + $view = id(new PHUITwoColumnView()) + ->setHeader($header) + ->setFooter($log_panel); + + return $this->newPage() + ->setTitle(pht('Combined Daemon Log')) + ->appendChild($view); - return $this->buildApplicationPage( - array( - $crumbs, - $log_panel, - ), - array( - 'title' => pht('Combined Daemon Log'), - )); } } diff --git a/src/applications/daemon/controller/PhabricatorDaemonLogListController.php b/src/applications/daemon/controller/PhabricatorDaemonLogListController.php index c1de0b892f..e5ef050d99 100644 --- a/src/applications/daemon/controller/PhabricatorDaemonLogListController.php +++ b/src/applications/daemon/controller/PhabricatorDaemonLogListController.php @@ -1,41 +1,40 @@ getViewer(); $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); $box = id(new PHUIObjectBoxView()) ->setHeaderText(pht('All Daemons')) ->appendChild($daemon_table); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('All Daemons')); $nav = $this->buildSideNavView(); $nav->selectFilter('log'); $nav->setCrumbs($crumbs); $nav->appendChild($box); $nav->appendChild($pager); - return $this->buildApplicationPage( - $nav, - array( - 'title' => pht('All Daemons'), - )); + return $this->newPage() + ->setTitle(pht('All Daemons')) + ->appendChild($nav); + } } diff --git a/src/applications/daemon/controller/PhabricatorDaemonLogViewController.php b/src/applications/daemon/controller/PhabricatorDaemonLogViewController.php index 32af8f6f13..f2f5121898 100644 --- a/src/applications/daemon/controller/PhabricatorDaemonLogViewController.php +++ b/src/applications/daemon/controller/PhabricatorDaemonLogViewController.php @@ -1,183 +1,194 @@ getViewer(); $id = $request->getURIData('id'); $log = id(new PhabricatorDaemonLogQuery()) ->setViewer($viewer) ->withIDs(array($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())); + $crumbs->setBorder(true); $header = id(new PHUIHeaderView()) - ->setHeader($log->getDaemon()); + ->setHeader($log->getDaemon()) + ->setHeaderIcon('fa-pied-piper-alt'); $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')); + $color = 'orange'; + $name = pht('Unknown'); + $icon = 'fa-warning'; break; case PhabricatorDaemonLog::STATUS_RUNNING: - $tag->setBackgroundColor(PHUITagView::COLOR_GREEN); - $tag->setName(pht('Running')); + $color = 'green'; + $name = pht('Running'); + $icon = 'fa-rocket'; break; case PhabricatorDaemonLog::STATUS_DEAD: - $tag->setBackgroundColor(PHUITagView::COLOR_RED); - $tag->setName(pht('Dead')); + $color = 'red'; + $name = pht('Dead'); + $icon = 'fa-times'; break; case PhabricatorDaemonLog::STATUS_WAIT: - $tag->setBackgroundColor(PHUITagView::COLOR_BLUE); - $tag->setName(pht('Waiting')); + $color = 'blue'; + $name = pht('Waiting'); + $icon = 'fa-clock-o'; break; case PhabricatorDaemonLog::STATUS_EXITING: - $tag->setBackgroundColor(PHUITagView::COLOR_YELLOW); - $tag->setName(pht('Exiting')); + $color = 'yellow'; + $name = pht('Exiting'); + $icon = 'fa-check'; break; case PhabricatorDaemonLog::STATUS_EXITED: - $tag->setBackgroundColor(PHUITagView::COLOR_GREY); - $tag->setName(pht('Exited')); + $color = 'bluegrey'; + $name = pht('Exited'); + $icon = 'fa-check'; break; } - $header->addTag($tag); + $header->setStatus($icon, $color, $name); $properties = $this->buildPropertyListView($log); $event_view = id(new PhabricatorDaemonLogEventsView()) ->setUser($viewer) ->setEvents($events); - $event_panel = new PHUIObjectBoxView(); - $event_panel->setHeaderText(pht('Events')); - $event_panel->appendChild($event_view); + $event_panel = id(new PHUIObjectBoxView()) + ->setHeaderText(pht('Events')) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->appendChild($event_view); $object_box = id(new PHUIObjectBoxView()) - ->setHeader($header) ->addPropertyList($properties); - return $this->buildApplicationPage( - array( - $crumbs, + $view = id(new PHUITwoColumnView()) + ->setHeader($header) + ->setFooter(array( $object_box, $event_panel, - ), - array( - 'title' => pht('Daemon Log'), )); + + return $this->newPage() + ->setTitle(pht('Daemon Log')) + ->setCrumbs($crumbs) + ->appendChild($view); + } 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 = PhutilDaemonHandle::getWaitBeforeRestart(); $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).', phutil_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.', phutil_format_relative_time($unknown_time), phutil_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.', phutil_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.', phutil_format_relative_time($unknown_time), phutil_format_relative_time($wait_time)); break; case PhabricatorDaemonLog::STATUS_EXITING: $details = pht('This daemon is shutting down gracefully.'); 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('Running as'), $daemon->getRunningAsUser()); $view->addProperty(pht('Started'), phabricator_datetime($c_epoch, $viewer)); $view->addProperty( pht('Seen'), pht( '%s ago (%s)', phutil_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 {$id}")); return $view; } } diff --git a/src/applications/daemon/controller/PhabricatorWorkerTaskDetailController.php b/src/applications/daemon/controller/PhabricatorWorkerTaskDetailController.php index ad8f673fd7..ad15d41b9d 100644 --- a/src/applications/daemon/controller/PhabricatorWorkerTaskDetailController.php +++ b/src/applications/daemon/controller/PhabricatorWorkerTaskDetailController.php @@ -1,218 +1,221 @@ getViewer(); $id = $request->getURIData('id'); $task = id(new PhabricatorWorkerActiveTask())->load($id); if (!$task) { $tasks = id(new PhabricatorWorkerArchiveTaskQuery()) ->withIDs(array($id)) ->execute(); $task = reset($tasks); } if (!$task) { $title = pht('Task Does Not Exist'); $error_view = new PHUIInfoView(); $error_view->setTitle(pht('No Such Task')); $error_view->appendChild(phutil_tag( 'p', array(), pht('This task may have recently been garbage collected.'))); $error_view->setSeverity(PHUIInfoView::SEVERITY_NODATA); $content = $error_view; } else { $title = pht('Task %d', $task->getID()); $header = id(new PHUIHeaderView()) - ->setHeader(pht('Task %d (%s)', + ->setHeader(pht('Task %d: %s', $task->getID(), - $task->getTaskClass())); + $task->getTaskClass())) + ->setHeaderIcon('fa-sort'); $properties = $this->buildPropertyListView($task); $object_box = id(new PHUIObjectBoxView()) - ->setHeader($header) + ->setHeaderText($title) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->addPropertyList($properties); - $retry_head = id(new PHUIHeaderView()) ->setHeader(pht('Retries')); $retry_info = $this->buildRetryListView($task); $retry_box = id(new PHUIObjectBoxView()) ->setHeader($retry_head) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->addPropertyList($retry_info); $content = array( $object_box, $retry_box, ); } $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($title); + $crumbs->setBorder(true); + + $view = id(new PHUITwoColumnView()) + ->setHeader($header) + ->setFooter($content); - return $this->buildApplicationPage( - array( - $crumbs, - $content, - ), - array( - 'title' => $title, - )); + return $this->newPage() + ->setTitle($title) + ->setCrumbs($crumbs) + ->appendChild($view); } private function buildPropertyListView( PhabricatorWorkerTask $task) { $viewer = $this->getRequest()->getUser(); $view = new PHUIPropertyListView(); if ($task->isArchived()) { switch ($task->getResult()) { case PhabricatorWorkerArchiveTask::RESULT_SUCCESS: $status = pht('Complete'); break; case PhabricatorWorkerArchiveTask::RESULT_FAILURE: $status = pht('Failed'); break; case PhabricatorWorkerArchiveTask::RESULT_CANCELLED: $status = pht('Cancelled'); break; default: throw new Exception(pht('Unknown task status!')); } } else { $status = pht('Queued'); } $view->addProperty( pht('Task Status'), $status); $view->addProperty( pht('Task Class'), $task->getTaskClass()); if ($task->getLeaseExpires()) { if ($task->getLeaseExpires() > time()) { $lease_status = pht('Leased'); } else { $lease_status = pht('Lease Expired'); } } else { $lease_status = phutil_tag('em', array(), pht('Not Leased')); } $view->addProperty( pht('Lease Status'), $lease_status); $view->addProperty( pht('Lease Owner'), $task->getLeaseOwner() ? $task->getLeaseOwner() : phutil_tag('em', array(), pht('None'))); if ($task->getLeaseExpires() && $task->getLeaseOwner()) { $expires = ($task->getLeaseExpires() - time()); $expires = phutil_format_relative_time_detailed($expires); } else { $expires = phutil_tag('em', array(), pht('None')); } $view->addProperty( pht('Lease Expires'), $expires); if ($task->isArchived()) { $duration = pht('%s us', new PhutilNumber($task->getDuration())); } else { $duration = phutil_tag('em', array(), pht('Not Completed')); } $view->addProperty( pht('Duration'), $duration); $data = id(new PhabricatorWorkerTaskData())->load($task->getDataID()); $task->setData($data->getData()); $worker = $task->getWorkerInstance(); $data = $worker->renderForDisplay($viewer); if ($data !== null) { $view->addProperty(pht('Data'), $data); } return $view; } private function buildRetryListView(PhabricatorWorkerTask $task) { $view = new PHUIPropertyListView(); $data = id(new PhabricatorWorkerTaskData())->load($task->getDataID()); $task->setData($data->getData()); $worker = $task->getWorkerInstance(); $view->addProperty( pht('Failure Count'), $task->getFailureCount()); $retry_count = $worker->getMaximumRetryCount(); if ($retry_count === null) { $max_retries = phutil_tag('em', array(), pht('Retries Forever')); $retry_count = INF; } else { $max_retries = $retry_count; } $view->addProperty( pht('Maximum Retries'), $max_retries); $projection = clone $task; $projection->makeEphemeral(); $next = array(); for ($ii = $task->getFailureCount(); $ii < $retry_count; $ii++) { $projection->setFailureCount($ii); $next[] = $worker->getWaitBeforeRetry($projection); if (count($next) > 10) { break; } } if ($next) { $cumulative = 0; foreach ($next as $key => $duration) { if ($duration === null) { $duration = 60; } $cumulative += $duration; $next[$key] = phutil_format_relative_time($cumulative); } if ($ii != $retry_count) { $next[] = '...'; } $retries_in = implode(', ', $next); } else { $retries_in = pht('No More Retries'); } $view->addProperty( pht('Retries After'), $retries_in); return $view; } }