fix(conductor): Apply review suggestions for track 'mma_data_architecture_dag_engine'
This commit is contained in:
@@ -1,13 +1,26 @@
|
||||
from typing import List
|
||||
from typing import List, Optional
|
||||
from models import Ticket
|
||||
|
||||
class TrackDAG:
|
||||
"""
|
||||
Manages a Directed Acyclic Graph of implementation tickets.
|
||||
Provides methods for dependency resolution, cycle detection, and topological sorting.
|
||||
"""
|
||||
def __init__(self, tickets: List[Ticket]):
|
||||
"""
|
||||
Initializes the TrackDAG with a list of Ticket objects.
|
||||
Args:
|
||||
tickets: A list of Ticket instances defining the graph nodes and edges.
|
||||
"""
|
||||
self.tickets = tickets
|
||||
self.ticket_map = {t.id: t for t in tickets}
|
||||
|
||||
def get_ready_tasks(self) -> List[Ticket]:
|
||||
"""Returns tickets that are 'todo' and whose dependencies are all 'completed'."""
|
||||
"""
|
||||
Returns a list of tickets that are in 'todo' status and whose dependencies are all 'completed'.
|
||||
Returns:
|
||||
A list of Ticket objects ready for execution.
|
||||
"""
|
||||
ready = []
|
||||
for ticket in self.tickets:
|
||||
if ticket.status == 'todo':
|
||||
@@ -23,11 +36,16 @@ class TrackDAG:
|
||||
return ready
|
||||
|
||||
def has_cycle(self) -> bool:
|
||||
"""Returns True if there's a dependency cycle."""
|
||||
"""
|
||||
Performs a Depth-First Search to detect cycles in the dependency graph.
|
||||
Returns:
|
||||
True if a cycle is detected, False otherwise.
|
||||
"""
|
||||
visited = set()
|
||||
rec_stack = set()
|
||||
|
||||
def is_cyclic(ticket_id):
|
||||
def is_cyclic(ticket_id: str) -> bool:
|
||||
"""Internal recursive helper for cycle detection."""
|
||||
if ticket_id in rec_stack:
|
||||
return True
|
||||
if ticket_id in visited:
|
||||
@@ -53,8 +71,11 @@ class TrackDAG:
|
||||
|
||||
def topological_sort(self) -> List[str]:
|
||||
"""
|
||||
Returns a list of ticket IDs in topological order.
|
||||
Raises ValueError if a cycle is detected.
|
||||
Returns a list of ticket IDs in topological order (dependencies before dependents).
|
||||
Returns:
|
||||
A list of ticket ID strings.
|
||||
Raises:
|
||||
ValueError: If a dependency cycle is detected.
|
||||
"""
|
||||
if self.has_cycle():
|
||||
raise ValueError("Dependency cycle detected")
|
||||
@@ -62,7 +83,8 @@ class TrackDAG:
|
||||
visited = set()
|
||||
stack = []
|
||||
|
||||
def visit(ticket_id):
|
||||
def visit(ticket_id: str):
|
||||
"""Internal recursive helper for topological sorting."""
|
||||
if ticket_id in visited:
|
||||
return
|
||||
visited.add(ticket_id)
|
||||
@@ -78,16 +100,26 @@ class TrackDAG:
|
||||
return stack
|
||||
|
||||
class ExecutionEngine:
|
||||
"""
|
||||
A state machine that governs the progression of tasks within a TrackDAG.
|
||||
Handles automatic queueing and manual task approval.
|
||||
"""
|
||||
def __init__(self, dag: TrackDAG, auto_queue: bool = False):
|
||||
"""
|
||||
Initializes the ExecutionEngine.
|
||||
Args:
|
||||
dag: The TrackDAG instance to manage.
|
||||
auto_queue: If True, ready tasks will automatically move to 'in_progress'.
|
||||
"""
|
||||
self.dag = dag
|
||||
self.auto_queue = auto_queue
|
||||
|
||||
def tick(self) -> List[Ticket]:
|
||||
"""
|
||||
Returns a list of tasks that are currently 'ready' to be executed.
|
||||
A task is ready if its status is 'todo' and all its dependencies are 'completed'.
|
||||
If auto_queue=True, it will automatically mark 'ready' tasks as 'in-progress',
|
||||
unless step_mode=True is set on the task.
|
||||
Evaluates the DAG and returns a list of tasks that are currently 'ready' for execution.
|
||||
If auto_queue is enabled, tasks without 'step_mode' will be marked as 'in_progress'.
|
||||
Returns:
|
||||
A list of ready Ticket objects.
|
||||
"""
|
||||
ready = self.dag.get_ready_tasks()
|
||||
|
||||
@@ -100,8 +132,9 @@ class ExecutionEngine:
|
||||
|
||||
def approve_task(self, task_id: str):
|
||||
"""
|
||||
Manually approves a task to move it to 'in_progress'.
|
||||
Typically used for tasks with step_mode=True or when auto_queue is False.
|
||||
Manually transitions a task from 'todo' to 'in_progress' if its dependencies are met.
|
||||
Args:
|
||||
task_id: The ID of the task to approve.
|
||||
"""
|
||||
ticket = self.dag.ticket_map.get(task_id)
|
||||
if ticket and ticket.status == "todo":
|
||||
@@ -112,13 +145,16 @@ class ExecutionEngine:
|
||||
if not dep or dep.status != "completed":
|
||||
all_done = False
|
||||
break
|
||||
|
||||
|
||||
if all_done:
|
||||
ticket.status = "in_progress"
|
||||
|
||||
def update_task_status(self, task_id: str, status: str):
|
||||
"""
|
||||
Updates the status of a specific task within the DAG.
|
||||
Force-updates the status of a specific task.
|
||||
Args:
|
||||
task_id: The ID of the task.
|
||||
status: The new status string (e.g., 'todo', 'in_progress', 'completed', 'blocked').
|
||||
"""
|
||||
ticket = self.dag.ticket_map.get(task_id)
|
||||
if ticket:
|
||||
|
||||
Reference in New Issue
Block a user