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 @@ -2518,13 +2518,15 @@ 'PhabricatorWorkerArchiveTask' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerArchiveTask.php', 'PhabricatorWorkerDAO' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerDAO.php', 'PhabricatorWorkerLeaseQuery' => 'infrastructure/daemon/workers/query/PhabricatorWorkerLeaseQuery.php', + 'PhabricatorWorkerManagementCancelWorkflow' => 'infrastructure/daemon/workers/management/PhabricatorWorkerManagementCancelWorkflow.php', 'PhabricatorWorkerManagementFloodWorkflow' => 'infrastructure/daemon/workers/management/PhabricatorWorkerManagementFloodWorkflow.php', + 'PhabricatorWorkerManagementFreeWorkflow' => 'infrastructure/daemon/workers/management/PhabricatorWorkerManagementFreeWorkflow.php', + 'PhabricatorWorkerManagementRetryWorkflow' => 'infrastructure/daemon/workers/management/PhabricatorWorkerManagementRetryWorkflow.php', 'PhabricatorWorkerManagementWorkflow' => 'infrastructure/daemon/workers/management/PhabricatorWorkerManagementWorkflow.php', 'PhabricatorWorkerPermanentFailureException' => 'infrastructure/daemon/workers/exception/PhabricatorWorkerPermanentFailureException.php', 'PhabricatorWorkerTask' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerTask.php', 'PhabricatorWorkerTaskData' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerTaskData.php', 'PhabricatorWorkerTaskDetailController' => 'applications/daemon/controller/PhabricatorWorkerTaskDetailController.php', - 'PhabricatorWorkerTaskUpdateController' => 'applications/daemon/controller/PhabricatorWorkerTaskUpdateController.php', 'PhabricatorWorkerTestCase' => 'infrastructure/daemon/workers/__tests__/PhabricatorWorkerTestCase.php', 'PhabricatorWorkerYieldException' => 'infrastructure/daemon/workers/exception/PhabricatorWorkerYieldException.php', 'PhabricatorWorkingCopyDiscoveryTestCase' => 'applications/repository/engine/__tests__/PhabricatorWorkingCopyDiscoveryTestCase.php', @@ -5702,13 +5704,15 @@ 'PhabricatorWorkerArchiveTask' => 'PhabricatorWorkerTask', 'PhabricatorWorkerDAO' => 'PhabricatorLiskDAO', 'PhabricatorWorkerLeaseQuery' => 'PhabricatorQuery', + 'PhabricatorWorkerManagementCancelWorkflow' => 'PhabricatorWorkerManagementWorkflow', 'PhabricatorWorkerManagementFloodWorkflow' => 'PhabricatorWorkerManagementWorkflow', + 'PhabricatorWorkerManagementFreeWorkflow' => 'PhabricatorWorkerManagementWorkflow', + 'PhabricatorWorkerManagementRetryWorkflow' => 'PhabricatorWorkerManagementWorkflow', 'PhabricatorWorkerManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorWorkerPermanentFailureException' => 'Exception', 'PhabricatorWorkerTask' => 'PhabricatorWorkerDAO', 'PhabricatorWorkerTaskData' => 'PhabricatorWorkerDAO', 'PhabricatorWorkerTaskDetailController' => 'PhabricatorDaemonController', - 'PhabricatorWorkerTaskUpdateController' => 'PhabricatorDaemonController', 'PhabricatorWorkerTestCase' => 'PhabricatorTestCase', 'PhabricatorWorkerYieldException' => 'Exception', 'PhabricatorWorkingCopyDiscoveryTestCase' => 'PhabricatorWorkingCopyTestCase', diff --git a/src/applications/daemon/application/PhabricatorDaemonsApplication.php b/src/applications/daemon/application/PhabricatorDaemonsApplication.php --- a/src/applications/daemon/application/PhabricatorDaemonsApplication.php +++ b/src/applications/daemon/application/PhabricatorDaemonsApplication.php @@ -41,8 +41,6 @@ '/daemon/' => array( '' => 'PhabricatorDaemonConsoleController', 'task/(?P[1-9]\d*)/' => 'PhabricatorWorkerTaskDetailController', - 'task/(?P[1-9]\d*)/(?P[^/]+)/' - => 'PhabricatorWorkerTaskUpdateController', 'log/' => array( '' => 'PhabricatorDaemonLogListController', '(?P[1-9]\d*)/' => 'PhabricatorDaemonLogViewController', diff --git a/src/applications/daemon/controller/PhabricatorWorkerTaskDetailController.php b/src/applications/daemon/controller/PhabricatorWorkerTaskDetailController.php --- a/src/applications/daemon/controller/PhabricatorWorkerTaskDetailController.php +++ b/src/applications/daemon/controller/PhabricatorWorkerTaskDetailController.php @@ -38,8 +38,7 @@ $task->getID(), $task->getTaskClass())); - $actions = $this->buildActionListView($task); - $properties = $this->buildPropertyListView($task, $actions); + $properties = $this->buildPropertyListView($task); $object_box = id(new PHUIObjectBoxView()) ->setHeader($header) @@ -74,57 +73,12 @@ )); } - 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('fa-refresh') - ->setWorkflow(true) - ->setDisabled(!$can_retry)); - } else { - $view->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Cancel Task')) - ->setHref($this->getApplicationURI('/task/'.$id.'/cancel/')) - ->setIcon('fa-times') - ->setWorkflow(true)); - } - - $can_release = (!$task->isArchived()) && - ($task->getLeaseOwner()); - - $view->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Free Lease')) - ->setHref($this->getApplicationURI('/task/'.$id.'/release/')) - ->setIcon('fa-unlock') - ->setWorkflow(true) - ->setDisabled(!$can_release)); - - return $view; - } - private function buildPropertyListView( - PhabricatorWorkerTask $task, - PhabricatorActionListView $actions) { + PhabricatorWorkerTask $task) { $viewer = $this->getRequest()->getUser(); $view = new PHUIPropertyListView(); - $view->setActionList($actions); if ($task->isArchived()) { switch ($task->getResult()) { diff --git a/src/applications/daemon/controller/PhabricatorWorkerTaskUpdateController.php b/src/applications/daemon/controller/PhabricatorWorkerTaskUpdateController.php deleted file mode 100644 --- a/src/applications/daemon/controller/PhabricatorWorkerTaskUpdateController.php +++ /dev/null @@ -1,120 +0,0 @@ -id = $data['id']; - $this->action = $data['action']; - } - - 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) { - return new Aphront404Response(); - } - - $result_success = PhabricatorWorkerArchiveTask::RESULT_SUCCESS; - $can_retry = ($task->isArchived()) && - ($task->getResult() != $result_success); - - $can_cancel = !$task->isArchived(); - $can_release = (!$task->isArchived()) && - ($task->getLeaseOwner()); - - $next_uri = $this->getApplicationURI('/task/'.$task->getID().'/'); - - if ($request->isFormPost()) { - switch ($this->action) { - case 'retry': - if ($can_retry) { - $task->unarchiveTask(); - } - break; - case 'cancel': - if ($can_cancel) { - // Forcibly break the lease if one exists, so we can archive the - // task. - $task->setLeaseOwner(null); - $task->setLeaseExpires(time()); - - $task->archiveTask( - PhabricatorWorkerArchiveTask::RESULT_CANCELLED, - 0); - } - break; - case 'release': - if ($can_release) { - $task->setLeaseOwner(null); - $task->setLeaseExpires(time()); - $task->save(); - } - break; - } - return id(new AphrontRedirectResponse()) - ->setURI($next_uri); - } - - $dialog = new AphrontDialogView(); - $dialog->setUser($user); - - switch ($this->action) { - case 'retry': - if ($can_retry) { - $dialog->setTitle(pht('Really retry task?')); - $dialog->appendChild(phutil_tag('p', array(), pht( - 'The task will be put back in the queue and executed again.'))); - $dialog->addSubmitButton('Retry Task'); - } else { - $dialog->setTitle(pht('Can Not Retry')); - $dialog->appendChild(phutil_tag('p', array(), pht( - 'Only archived, unsuccessful tasks can be retried.'))); - } - break; - case 'cancel': - if ($can_cancel) { - $dialog->setTitle(pht('Really cancel task?')); - $dialog->appendChild(phutil_tag('p', array(), pht( - 'The work this task represents will never be performed if you '. - 'cancel it. Are you sure you want to cancel it?'))); - $dialog->addSubmitButton(pht('Cancel Task')); - } else { - $dialog->setTitle(pht('Cannot Cancel')); - $dialog->appendChild(phutil_tag('p', array(), pht( - 'Only active tasks can be cancelled.'))); - } - break; - case 'release': - if ($can_release) { - $dialog->setTitle(pht('Really free task lease?')); - $dialog->appendChild(phutil_tag('p', array(), pht( - 'If the process which owns the task lease is still doing work '. - 'on it, the work may be performed twice. Are you sure you '. - 'want to free the lease?'))); - $dialog->addSubmitButton(pht('Free Lease')); - } else { - $dialog->setTitle(pht('Cannot Free Lease')); - $dialog->appendChild(phutil_tag('p', array(), pht( - 'Only active, leased tasks may have their leases freed.'))); - } - break; - default: - return new Aphront404Response(); - } - - $dialog->addCancelButton($next_uri); - - return id(new AphrontDialogResponse())->setDialog($dialog); - } - -} diff --git a/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementCancelWorkflow.php b/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementCancelWorkflow.php new file mode 100644 --- /dev/null +++ b/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementCancelWorkflow.php @@ -0,0 +1,52 @@ +setName('cancel') + ->setExamples('**cancel** --id __id__') + ->setSynopsis( + pht( + 'Cancel selected tasks. The work these tasks represent will never '. + 'be performed.')) + ->setArguments($this->getTaskSelectionArguments()); + } + + public function execute(PhutilArgumentParser $args) { + $console = PhutilConsole::getConsole(); + $tasks = $this->loadTasks($args); + + foreach ($tasks as $task) { + $can_cancel = !$task->isArchived(); + if (!$can_cancel) { + $console->writeOut( + "** %s ** %s\n", + pht('ARCHIVED'), + pht( + '%s is already archived, and can not be cancelled.', + $this->describeTask($task))); + continue; + } + + // Forcibly break the lease if one exists, so we can archive the + // task. + $task->setLeaseOwner(null); + $task->setLeaseExpires(PhabricatorTime::getNow()); + $task->archiveTask( + PhabricatorWorkerArchiveTask::RESULT_CANCELLED, + 0); + + $console->writeOut( + "** %s ** %s\n", + pht('CANCELLED'), + pht( + '%s was cancelled.', + $this->describeTask($task))); + } + + return 0; + } + +} diff --git a/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementFreeWorkflow.php b/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementFreeWorkflow.php new file mode 100644 --- /dev/null +++ b/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementFreeWorkflow.php @@ -0,0 +1,58 @@ +setName('free') + ->setExamples('**free** --id __id__') + ->setSynopsis( + pht( + 'Free leases on selected tasks. If the daemon holding the lease is '. + 'still working on the task, this may cause the task to execute '. + 'twice.')) + ->setArguments($this->getTaskSelectionArguments()); + } + + public function execute(PhutilArgumentParser $args) { + $console = PhutilConsole::getConsole(); + $tasks = $this->loadTasks($args); + + foreach ($tasks as $task) { + if ($task->isArchived()) { + $console->writeOut( + "** %s ** %s\n", + pht('ARCHIVED'), + pht( + '%s is archived; archived tasks do not have leases.', + $this->describeTask($task))); + continue; + } + + if ($task->getLeaseOwner() === null) { + $console->writeOut( + "** %s ** %s\n", + pht('FREE'), + pht( + '%s has no active lease.', + $this->describeTask($task))); + continue; + } + + $task->setLeaseOwner(null); + $task->setLeaseExpires(PhabricatorTime::getNow()); + $task->save(); + + $console->writeOut( + "** %s ** %s\n", + pht('LEASE FREED'), + pht( + '%s was freed from its lease.', + $this->describeTask($task))); + } + + return 0; + } + +} diff --git a/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementRetryWorkflow.php b/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementRetryWorkflow.php new file mode 100644 --- /dev/null +++ b/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementRetryWorkflow.php @@ -0,0 +1,57 @@ +setName('retry') + ->setExamples('**retry** --id __id__') + ->setSynopsis( + pht( + 'Retry selected tasks which previously failed permanently or '. + 'were cancelled. Only archived, unsuccessful tasks can be '. + 'retried.')) + ->setArguments($this->getTaskSelectionArguments()); + } + + public function execute(PhutilArgumentParser $args) { + $console = PhutilConsole::getConsole(); + $tasks = $this->loadTasks($args); + + foreach ($tasks as $task) { + if (!$task->isArchived()) { + $console->writeOut( + "** %s ** %s\n", + pht('ACTIVE'), + pht( + '%s is already in the active task queue.', + $this->describeTask($task))); + continue; + } + + $result_success = PhabricatorWorkerArchiveTask::RESULT_SUCCESS; + if ($task->getResult() == $result_success) { + $console->writeOut( + "** %s ** %s\n", + pht('SUCCEEDED'), + pht( + '%s has already succeeded, and can not be retried.', + $this->describeTask($task))); + continue; + } + + $task->unarchiveTask(); + + $console->writeOut( + "** %s ** %s\n", + pht('QUEUED'), + pht( + '%s was queued for retry.', + $this->describeTask($task))); + } + + return 0; + } + +} diff --git a/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementWorkflow.php b/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementWorkflow.php --- a/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementWorkflow.php +++ b/src/infrastructure/daemon/workers/management/PhabricatorWorkerManagementWorkflow.php @@ -1,4 +1,49 @@ 'id', + 'param' => 'id', + 'repeat' => true, + 'help' => pht('Select one or more tasks by ID.'), + ), + ); + } + + protected function loadTasks(PhutilArgumentParser $args) { + $ids = $args->getArg('id'); + if (!$ids) { + throw new PhutilArgumentUsageException( + pht('Use --id to select tasks by ID.')); + } + + $active_tasks = id(new PhabricatorWorkerActiveTask())->loadAllWhere( + 'id IN (%Ls)', + $ids); + $archive_tasks = id(new PhabricatorWorkerArchiveTask())->loadAllWhere( + 'id IN (%Ls)', + $ids); + + $tasks = + mpull($active_tasks, null, 'getID') + + mpull($archive_tasks, null, 'getID'); + + foreach ($ids as $id) { + if (empty($tasks[$id])) { + throw new PhutilArgumentUsageException( + pht('No task exists with id "%s"!', $id)); + } + } + + return $tasks; + } + + protected function describeTask(PhabricatorWorkerTask $task) { + return pht('Task %d (%s)', $task->getID(), $task->getTaskClass()); + } + +}