diff --git a/src/ska_tango_base/base/task_queue_manager.py b/src/ska_tango_base/base/task_queue_manager.py index ca4556bae426d15c4b74cd9d78c41f6827830d34..d5d5913ce5ab1efeb4bfda321e869928bcc9547b 100644 --- a/src/ska_tango_base/base/task_queue_manager.py +++ b/src/ska_tango_base/base/task_queue_manager.py @@ -167,7 +167,9 @@ import logging import threading import time import traceback +from uuid import uuid4 from queue import Empty, Queue +from datetime import datetime from threading import Event from typing import Any, Callable, Dict, Optional, Tuple from dataclasses import dataclass @@ -211,6 +213,31 @@ class TaskState(enum.IntEnum): """ +@dataclass +class TaskUniqueId: + """Convenience class for the unique ID of a task.""" + + id_uuid: str + id_datetime: datetime + id_task_name: str + + @classmethod + def generate_unique_id(cls, task_name: str) -> str: + """Return a new unique ID.""" + return f"{uuid4()}_{time.time()}_{task_name}" + + @classmethod + def from_unique_id(cls, unique_id: str): + """Parse a unique ID.""" + parts = unique_id.split("_") + id_uuid = parts[0] + id_datetime = datetime.fromtimestamp(float(parts[1])) + id_task_name = "_".join(parts[2:]) + return TaskUniqueId( + id_uuid=id_uuid, id_datetime=id_datetime, id_task_name=id_task_name + ) + + @dataclass class TaskResult: """Convenience class for results.""" @@ -265,6 +292,10 @@ class TaskResult: unique_id=command_result[1], ) + def get_task_unique_id(self) -> TaskUniqueId: + """Convert from the unique_id string to TaskUniqueId.""" + return TaskUniqueId.from_unique_id(self.unique_id) + class QueueTask: """A task that can be put on the queue.""" @@ -580,7 +611,7 @@ class QueueManager: :return: The unique ID of the command :rtype: string """ - unique_id = self.get_unique_id(task.get_task_name()) + unique_id = self.generate_unique_id(task.get_task_name()) # Inject the events into the task task.kwargs["aborting_event"] = self.aborting_event @@ -677,7 +708,7 @@ class QueueManager: return self.aborting_event.is_set() @classmethod - def get_unique_id(cls, task_name) -> str: + def generate_unique_id(cls, task_name) -> str: """Generate a unique ID for the task. :param task_name: The name of the task @@ -685,7 +716,7 @@ class QueueManager: :return: The unique ID of the task :rtype: string """ - return f"{time.time()}_{task_name}" + return TaskUniqueId.generate_unique_id(task_name) def get_task_state(self, unique_id: str) -> TaskState: """Attempt to get state of QueueTask. diff --git a/tests/test_reference_base_device.py b/tests/test_reference_base_device.py index 563d21f44d10450d4d04d4fdbb8a9cb29fc71096..cf62c30744c86e2929b5349e71be3e63962468b6 100644 --- a/tests/test_reference_base_device.py +++ b/tests/test_reference_base_device.py @@ -42,7 +42,7 @@ class TestCommands: result = TaskResult.from_task_result(proxy.longRunningCommandResult) assert result.result_code == ResultCode.OK - assert result.unique_id.endswith("SimpleTask") + assert result.get_task_unique_id().id_task_name == "SimpleTask" @pytest.mark.timeout(5) def test_non_aborting_command(self): @@ -55,7 +55,7 @@ class TestCommands: pass result = TaskResult.from_task_result(proxy.longRunningCommandResult) assert result.result_code == ResultCode.OK - assert result.unique_id.endswith("NonAbortingTask") + assert result.get_task_unique_id().id_task_name == "NonAbortingTask" @pytest.mark.timeout(5) def test_aborting_command(self): @@ -155,7 +155,7 @@ def test_callbacks(): # longRunningCommandResult assert len(attribute_values[10]) == 3 tr = TaskResult.from_task_result(attribute_values[10]) - tr.unique_id.endswith("ProgressTask") + assert tr.get_task_unique_id().id_task_name == "ProgressTask" tr.result_code == ResultCode.OK tr.task_result == "None"