diff --git a/flower/api/tasks.py b/flower/api/tasks.py index 730c290e..6a9c5dd7 100644 --- a/flower/api/tasks.py +++ b/flower/api/tasks.py @@ -14,6 +14,7 @@ from ..utils import tasks from ..utils.broker import Broker +from ..utils.tasks import parse_args, parse_kwargs, make_json_serializable from . import BaseApiHandler logger = logging.getLogger(__name__) @@ -636,3 +637,50 @@ def get(self, taskid): response['worker'] = task.worker.hostname self.write(response) + +class TaskReapply(BaseTaskHandler): + @web.authenticated + async def post(self, taskid): + """ + Get task info and reapply the task with the same arguments. + + :param taskid: ID of the task to reapply. + """ + # Get original task info + task = tasks.get_task_by_id(self.application.events, taskid) + if not task: + raise HTTPError(404, f"Unknown task '{taskid}'") + + # Get task name + taskname = task.name + if not taskname: + raise HTTPError(400, "Cannot reapply task with no name") + + try: + # Get the task object from registered tasks + task_obj = self.capp.tasks[taskname] + except KeyError as exc: + raise HTTPError(404, f"Unknown task '{taskname}'") from exc + + # Parse args and kwargs from the original task + try: + args = parse_args(task.args) + kwargs = parse_kwargs(task.kwargs) + except Exception as exc: + logger.error("Error parsing task arguments: %s", exc) + raise HTTPError(400, f"Invalid task arguments: {str(exc)}") from exc + + # Apply the task with original arguments + try: + # Ensure args and kwargs are JSON serializable + args = make_json_serializable(args) + kwargs = make_json_serializable(kwargs) + + result = task_obj.apply_async(args=args, kwargs=kwargs) + response = {'task-id': result.task_id} + if self.backend_configured(result): + response.update(state=result.state) + self.write(response) + except Exception as exc: + logger.error("Error reapplying task with args=%s, kwargs=%s: %s", args, kwargs, str(exc)) + raise HTTPError(500, f"Error reapplying task: {str(exc)}") from exc diff --git a/flower/static/js/flower.js b/flower/static/js/flower.js index 6edde42b..b1370673 100644 --- a/flower/static/js/flower.js +++ b/flower/static/js/flower.js @@ -690,4 +690,37 @@ var flower = (function () { }); + $('#task-retry').click(function () { + const $button = $(this); + const $spinner = $button.find('.spinner-border'); + const taskId = $('#taskid').text(); + + if (!taskId) { + show_alert('Task ID is missing. Cannot proceed.', 'danger'); + return; + } + + // Show loading state + $button.prop('disabled', true); + $spinner.removeClass('d-none'); + + // Reapply the task using the reapply endpoint + $.ajax({ + type: 'POST', + url: url_prefix() + '/api/task/reapply/' + taskId, + success: function (response) { + show_alert(`Task ${taskId} has been retried (new task ID: ${response['task-id']})`, 'success'); + // Optionally reload the page after success + setTimeout(() => location.reload(), 1500); + }, + error: function (response) { + show_alert(response.responseText || 'Failed to retry task', 'danger'); + // Reset button state on error + $button.prop('disabled', false); + $spinner.addClass('d-none'); + } + }); + }); + + }(jQuery)); diff --git a/flower/templates/task.html b/flower/templates/task.html index 8d66bb08..5a8c3732 100644 --- a/flower/templates/task.html +++ b/flower/templates/task.html @@ -16,6 +16,11 @@