mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-10 08:52:39 +01:00
Move cancel/retry/free task queue actions to bin/worker
Summary: Fixes T6702. Ref T3554. Currently, tasks can be cancelled, retried and freed from the web UI by any logged in user. This isn't appreciably dangerous (I can't come up with a way that a user could do anything security-affecting), but I think I probably intended this to be admin-only, but these actions should move to the CLI anyway. Move them to the CLI. Lay some groundwork for some future `bin/worker cancel --class SomeTaskClass`, but don't implement that yet. Test Plan: Used `cancel`, `retry` and `free` from the CLI. Hit all the error/success states. Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T3554, T6702 Differential Revision: https://secure.phabricator.com/D10939
This commit is contained in:
parent
a0907819cd
commit
9a7383121d
8 changed files with 221 additions and 173 deletions
|
@ -2518,13 +2518,15 @@ phutil_register_library_map(array(
|
|||
'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 @@ phutil_register_library_map(array(
|
|||
'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',
|
||||
|
|
|
@ -41,8 +41,6 @@ final class PhabricatorDaemonsApplication extends PhabricatorApplication {
|
|||
'/daemon/' => array(
|
||||
'' => 'PhabricatorDaemonConsoleController',
|
||||
'task/(?P<id>[1-9]\d*)/' => 'PhabricatorWorkerTaskDetailController',
|
||||
'task/(?P<id>[1-9]\d*)/(?P<action>[^/]+)/'
|
||||
=> 'PhabricatorWorkerTaskUpdateController',
|
||||
'log/' => array(
|
||||
'' => 'PhabricatorDaemonLogListController',
|
||||
'(?P<id>[1-9]\d*)/' => 'PhabricatorDaemonLogViewController',
|
||||
|
|
|
@ -38,8 +38,7 @@ final class PhabricatorWorkerTaskDetailController
|
|||
$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 @@ final class PhabricatorWorkerTaskDetailController
|
|||
));
|
||||
}
|
||||
|
||||
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()) {
|
||||
|
|
|
@ -1,120 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorWorkerTaskUpdateController
|
||||
extends PhabricatorDaemonController {
|
||||
|
||||
private $id;
|
||||
private $action;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->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);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorWorkerManagementCancelWorkflow
|
||||
extends PhabricatorWorkerManagementWorkflow {
|
||||
|
||||
public function didConstruct() {
|
||||
$this
|
||||
->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(
|
||||
"**<bg:yellow> %s </bg>** %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(
|
||||
"**<bg:green> %s </bg>** %s\n",
|
||||
pht('CANCELLED'),
|
||||
pht(
|
||||
'%s was cancelled.',
|
||||
$this->describeTask($task)));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorWorkerManagementFreeWorkflow
|
||||
extends PhabricatorWorkerManagementWorkflow {
|
||||
|
||||
public function didConstruct() {
|
||||
$this
|
||||
->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(
|
||||
"**<bg:yellow> %s </bg>** %s\n",
|
||||
pht('ARCHIVED'),
|
||||
pht(
|
||||
'%s is archived; archived tasks do not have leases.',
|
||||
$this->describeTask($task)));
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($task->getLeaseOwner() === null) {
|
||||
$console->writeOut(
|
||||
"**<bg:yellow> %s </bg>** %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(
|
||||
"**<bg:green> %s </bg>** %s\n",
|
||||
pht('LEASE FREED'),
|
||||
pht(
|
||||
'%s was freed from its lease.',
|
||||
$this->describeTask($task)));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorWorkerManagementRetryWorkflow
|
||||
extends PhabricatorWorkerManagementWorkflow {
|
||||
|
||||
public function didConstruct() {
|
||||
$this
|
||||
->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(
|
||||
"**<bg:yellow> %s </bg>** %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(
|
||||
"**<bg:yellow> %s </bg>** %s\n",
|
||||
pht('SUCCEEDED'),
|
||||
pht(
|
||||
'%s has already succeeded, and can not be retried.',
|
||||
$this->describeTask($task)));
|
||||
continue;
|
||||
}
|
||||
|
||||
$task->unarchiveTask();
|
||||
|
||||
$console->writeOut(
|
||||
"**<bg:green> %s </bg>** %s\n",
|
||||
pht('QUEUED'),
|
||||
pht(
|
||||
'%s was queued for retry.',
|
||||
$this->describeTask($task)));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,4 +1,49 @@
|
|||
<?php
|
||||
|
||||
abstract class PhabricatorWorkerManagementWorkflow
|
||||
extends PhabricatorManagementWorkflow {}
|
||||
extends PhabricatorManagementWorkflow {
|
||||
|
||||
protected function getTaskSelectionArguments() {
|
||||
return array(
|
||||
array(
|
||||
'name' => '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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue