def stop_task( task_id: str, company_id: str, user_name: str, status_reason: str, force: bool, ) -> dict: """ Stop a running task. Requires task status 'in_progress' and execution_progress 'running', or force=True. Development task or task that has no associated worker is stopped immediately. For a non-development task with worker only the status message is set to 'stopping' to allow the worker to stop the task and report by itself :return: updated task fields """ task = TaskBLL.get_task_with_access( task_id, company_id=company_id, only=( "status", "project", "tags", "system_tags", "last_worker", "last_update", "execution.queue", ), requires_write_access=True, ) def is_run_by_worker(t: Task) -> bool: """Checks if there is an active worker running the task""" update_timeout = config.get("apiserver.workers.task_update_timeout", 600) return ( t.last_worker and t.last_update and (datetime.utcnow() - t.last_update).total_seconds() < update_timeout ) is_queued = task.status == TaskStatus.queued set_stopped = ( is_queued or TaskSystemTags.development in task.system_tags or not is_run_by_worker(task) ) if set_stopped: if is_queued: try: TaskBLL.dequeue(task, company_id=company_id, silent_fail=True) except APIError: # dequeue may fail if the task was not enqueued pass new_status = TaskStatus.stopped status_message = f"Stopped by {user_name}" else: new_status = task.status status_message = TaskStatusMessage.stopping return ChangeStatusRequest( task=task, new_status=new_status, status_reason=status_reason, status_message=status_message, force=force, ).execute()
def reset(call: APICall, company_id, request: ResetRequest): task = TaskBLL.get_task_with_access( request.task, company_id=company_id, requires_write_access=True ) force = request.force if not force and task.status == TaskStatus.published: raise errors.bad_request.InvalidTaskStatus(task_id=task.id, status=task.status) api_results = {} updates = {} try: dequeued = TaskBLL.dequeue(task, company_id, silent_fail=True) except APIError: # dequeue may fail if the task was not enqueued pass else: if dequeued: api_results.update(dequeued=dequeued) cleaned_up = cleanup_task(task, force) api_results.update(attr.asdict(cleaned_up)) updates.update( set__last_iteration=DEFAULT_LAST_ITERATION, set__last_metrics={}, set__metric_stats={}, unset__output__result=1, unset__output__model=1, unset__output__error=1, unset__last_worker=1, unset__last_worker_report=1, ) if request.clear_all: updates.update( set__execution=Execution(), unset__script=1, ) else: updates.update(unset__execution__queue=1) if task.execution and task.execution.artifacts: updates.update( set__execution__artifacts={ key: artifact for key, artifact in task.execution.artifacts.items() if artifact.mode == ArtifactModes.input } ) res = ResetResponse( **ChangeStatusRequest( task=task, new_status=TaskStatus.created, force=force, status_reason="reset", status_message="reset", ).execute( started=None, completed=None, published=None, active_duration=None, **updates, ) ) # do not return artifacts since they are not serializable res.fields.pop("execution.artifacts", None) for key, value in api_results.items(): setattr(res, key, value) call.result.data_model = res
def reset_task( task_id: str, company_id: str, force: bool, return_file_urls: bool, delete_output_models: bool, clear_all: bool, ) -> Tuple[dict, CleanupResult, dict]: task = TaskBLL.get_task_with_access( task_id, company_id=company_id, requires_write_access=True ) if not force and task.status == TaskStatus.published: raise errors.bad_request.InvalidTaskStatus(task_id=task.id, status=task.status) dequeued = {} updates = {} try: dequeued = TaskBLL.dequeue(task, company_id, silent_fail=True) except APIError: # dequeue may fail if the task was not enqueued pass cleaned_up = cleanup_task( task, force=force, update_children=False, return_file_urls=return_file_urls, delete_output_models=delete_output_models, ) updates.update( set__last_iteration=DEFAULT_LAST_ITERATION, set__last_metrics={}, set__metric_stats={}, set__models__output=[], set__runtime={}, unset__output__result=1, unset__output__error=1, unset__last_worker=1, unset__last_worker_report=1, ) if clear_all: updates.update( set__execution=Execution(), unset__script=1, ) else: updates.update(unset__execution__queue=1) if task.execution and task.execution.artifacts: updates.update( set__execution__artifacts={ key: artifact for key, artifact in task.execution.artifacts.items() if artifact.mode == ArtifactModes.input } ) res = ChangeStatusRequest( task=task, new_status=TaskStatus.created, force=force, status_reason="reset", status_message="reset", ).execute( started=None, completed=None, published=None, active_duration=None, enqueue_status=None, **updates, ) return dequeued, cleaned_up, res