diff --git a/src/applications/daemon/controller/PhabricatorWorkerTaskDetailController.php b/src/applications/daemon/controller/PhabricatorWorkerTaskDetailController.php index 68b75ba06d..04ec5a4490 100644 --- a/src/applications/daemon/controller/PhabricatorWorkerTaskDetailController.php +++ b/src/applications/daemon/controller/PhabricatorWorkerTaskDetailController.php @@ -1,262 +1,268 @@ id = $data['id']; } public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $task = id(new PhabricatorWorkerActiveTask())->load($this->id); if (!$task) { $task = id(new PhabricatorWorkerArchiveTask())->load($this->id); } if (!$task) { $title = pht('Task Does Not Exist'); $error_view = new AphrontErrorView(); $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(AphrontErrorView::SEVERITY_NODATA); $content = $error_view; } else { $title = pht('Task %d', $task->getID()); $header = id(new PHUIHeaderView()) ->setHeader(pht('Task %d (%s)', $task->getID(), $task->getTaskClass())); $actions = $this->buildActionListView($task); $properties = $this->buildPropertyListView($task, $actions); + $object_box = id(new PHUIObjectBoxView()) + ->setHeader($header) + ->addPropertyList($properties); + + $retry_head = id(new PHUIHeaderView()) ->setHeader(pht('Retries')); $retry_info = $this->buildRetryListView($task); - $object_box = id(new PHUIObjectBoxView()) - ->setHeader($header) - ->addPropertyList($properties); + $retry_box = id(new PHUIObjectBoxView()) + ->setHeader($retry_head) + ->addPropertyList($retry_info); $content = array( $object_box, - $retry_head, - $retry_info, + $retry_box, ); } $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($title); return $this->buildApplicationPage( array( $crumbs, $content, ), array( 'title' => $title, 'device' => true, )); } private function buildActionListView(PhabricatorWorkerTask $task) { $request = $this->getRequest(); $user = $request->getUser(); $id = $task->getID(); $view = id(new PhabricatorActionListView()) ->setUser($user) ->setObjectURI($request->getRequestURI()); if ($task->isArchived()) { $result_success = PhabricatorWorkerArchiveTask::RESULT_SUCCESS; $can_retry = ($task->getResult() != $result_success); $view->addAction( id(new PhabricatorActionView()) ->setName(pht('Retry Task')) ->setHref($this->getApplicationURI('/task/'.$id.'/retry/')) ->setIcon('undo') ->setWorkflow(true) ->setDisabled(!$can_retry)); } else { $view->addAction( id(new PhabricatorActionView()) ->setName(pht('Cancel Task')) ->setHref($this->getApplicationURI('/task/'.$id.'/cancel/')) ->setIcon('delete') ->setWorkflow(true)); } $can_release = (!$task->isArchived()) && ($task->getLeaseOwner()); $view->addAction( id(new PhabricatorActionView()) ->setName(pht('Free Lease')) ->setHref($this->getApplicationURI('/task/'.$id.'/release/')) ->setIcon('unlock') ->setWorkflow(true) ->setDisabled(!$can_release)); return $view; } private function buildPropertyListView( PhabricatorWorkerTask $task, PhabricatorActionListView $actions) { + $viewer = $this->getRequest()->getUser(); + $view = new PHUIPropertyListView(); $view->setActionList($actions); 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("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 = phabricator_format_relative_time_detailed($expires); } else { $expires = phutil_tag('em', array(), pht('None')); } $view->addProperty( pht('Lease Expires'), $expires); if ($task->isArchived()) { $duration = number_format($task->getDuration()).' us'; } 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(); + $data = $worker->renderForDisplay($viewer); $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] = phabricator_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; } } diff --git a/src/applications/metamta/PhabricatorMetaMTAWorker.php b/src/applications/metamta/PhabricatorMetaMTAWorker.php index 50e0b38230..7d218e5fd8 100644 --- a/src/applications/metamta/PhabricatorMetaMTAWorker.php +++ b/src/applications/metamta/PhabricatorMetaMTAWorker.php @@ -1,52 +1,52 @@ loadMessage(); if (!$message) { return null; } $wait = max($message->getNextRetry() - time(), 0) + 15; return $wait; } public function doWork() { $message = $this->loadMessage(); if (!$message || $message->getStatus() != PhabricatorMetaMTAMail::STATUS_QUEUE) { return; } $id = $message->getID(); $message->sendNow(); // task failed if the message is still queued // (instead of sent, void, or failed) if ($message->getStatus() == PhabricatorMetaMTAMail::STATUS_QUEUE) { throw new Exception('Failed to send message'); } } private function loadMessage() { if (!$this->message) { $message_id = $this->getTaskData(); $this->message = id(new PhabricatorMetaMTAMail())->load($message_id); if (!$this->message) { return null; } } return $this->message; } - public function renderForDisplay() { + public function renderForDisplay(PhabricatorUser $viewer) { return phutil_tag( 'pre', array( ), 'phabricator/ $ ./bin/mail show-outbound --id '.$this->getTaskData()); } } diff --git a/src/applications/repository/worker/PhabricatorRepositoryCommitParserWorker.php b/src/applications/repository/worker/PhabricatorRepositoryCommitParserWorker.php index 607b80de46..3c1a6563d8 100644 --- a/src/applications/repository/worker/PhabricatorRepositoryCommitParserWorker.php +++ b/src/applications/repository/worker/PhabricatorRepositoryCommitParserWorker.php @@ -1,82 +1,84 @@ commit) { return $this->commit; } $commit_id = idx($this->getTaskData(), 'commitID'); if (!$commit_id) { return false; } $commit = id(new PhabricatorRepositoryCommit())->load($commit_id); if (!$commit) { // TODO: Communicate permanent failure? return false; } return $this->commit = $commit; } final public function doWork() { if (!$this->loadCommit()) { return; } $repository = id(new PhabricatorRepositoryQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withIDs(array($this->commit->getRepositoryID())) ->executeOne(); if (!$repository) { return; } $this->repository = $repository; return $this->parseCommit($repository, $this->commit); } final protected function shouldQueueFollowupTasks() { return !idx($this->getTaskData(), 'only'); } abstract protected function parseCommit( PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit); protected function isBadCommit($full_commit_name) { $repository = new PhabricatorRepository(); $bad_commit = queryfx_one( $repository->establishConnection('w'), 'SELECT * FROM %T WHERE fullCommitName = %s', PhabricatorRepository::TABLE_BADCOMMIT, $full_commit_name); return (bool)$bad_commit; } - public function renderForDisplay() { - $suffix = parent::renderForDisplay(); - $commit = $this->loadCommit(); + public function renderForDisplay(PhabricatorUser $viewer) { + $suffix = parent::renderForDisplay($viewer); + + $commit = id(new DiffusionCommitQuery()) + ->setViewer($viewer) + ->withIDs(array(idx($this->getTaskData(), 'commitID'))) + ->executeOne(); if (!$commit) { return $suffix; } - // TODO: (T603) This method should probably take a viewer. + $link = DiffusionView::linkCommit( + $commit->getRepository(), + $commit->getCommitIdentifier()); - $repository = id(new PhabricatorRepository()) - ->load($commit->getRepositoryID()); - $link = DiffusionView::linkCommit($repository, - $commit->getCommitIdentifier()); - return hsprintf('%s%s', $link, $suffix); + return array($link, $suffix); } } diff --git a/src/infrastructure/daemon/workers/PhabricatorWorker.php b/src/infrastructure/daemon/workers/PhabricatorWorker.php index a6096919f0..cc92cccec8 100644 --- a/src/infrastructure/daemon/workers/PhabricatorWorker.php +++ b/src/infrastructure/daemon/workers/PhabricatorWorker.php @@ -1,178 +1,178 @@ data = $data; } final protected function getTaskData() { return $this->data; } final public function executeTask() { $this->doWork(); } final public static function scheduleTask($task_class, $data) { if (self::$runAllTasksInProcess) { $worker = newv($task_class, array($data)); $worker->doWork(); } else { return id(new PhabricatorWorkerActiveTask()) ->setTaskClass($task_class) ->setData($data) ->save(); } } /** * Wait for tasks to complete. If tasks are not leased by other workers, they * will be executed in this process while waiting. * * @param list List of queued task IDs to wait for. * @return void */ final public static function waitForTasks(array $task_ids) { $task_table = new PhabricatorWorkerActiveTask(); $waiting = array_fuse($task_ids); while ($waiting) { $conn_w = $task_table->establishConnection('w'); // Check if any of the tasks we're waiting on are still queued. If they // are not, we're done waiting. $row = queryfx_one( $conn_w, 'SELECT COUNT(*) N FROM %T WHERE id IN (%Ld)', $task_table->getTableName(), $waiting); if (!$row['N']) { // Nothing is queued anymore. Stop waiting. break; } $tasks = id(new PhabricatorWorkerLeaseQuery()) ->withIDs($waiting) ->setLimit(1) ->execute(); if (!$tasks) { // We were not successful in leasing anything. Sleep for a bit and // see if we have better luck later. sleep(1); continue; } $task = head($tasks)->executeTask(); $ex = $task->getExecutionException(); if ($ex) { throw $ex; } } $tasks = id(new PhabricatorWorkerArchiveTask())->loadAllWhere( 'id IN (%Ld)', $task_ids); foreach ($tasks as $task) { if ($task->getResult() != PhabricatorWorkerArchiveTask::RESULT_SUCCESS) { throw new Exception("Task ".$task->getID()." failed!"); } } } - public function renderForDisplay() { + public function renderForDisplay(PhabricatorUser $viewer) { $data = PhutilReadableSerializer::printableValue($this->data); return phutil_tag('pre', array(), $data); } /** * Set this flag to execute scheduled tasks synchronously, in the same * process. This is useful for debugging, and otherwise dramatically worse * in every way imaginable. */ public static function setRunAllTasksInProcess($all) { self::$runAllTasksInProcess = $all; } protected function log($pattern /* $args */) { $console = PhutilConsole::getConsole(); $argv = func_get_args(); call_user_func_array(array($console, 'writeLog'), $argv); return $this; } }