Add First Version Of Workflow Layer Codes

This commit is contained in:
soorena62
2026-02-16 02:11:24 +03:30
commit c1f28e08b6
8 changed files with 780 additions and 0 deletions
+113
View File
@@ -0,0 +1,113 @@
from __future__ import annotations
from abc import ABC, abstractmethod
from typing import Any, Dict, List, Optional
from datetime import datetime
from enum import Enum
class Status(Enum):
PENDING = "pending"
READY = "ready"
RUNNING = "running"
PAUSED = "paused"
STOPPED = "stopped"
COMPLETED = "completed"
FAILED = "failed"
class TaskEvent(Enum):
BEFORE_RUN = "before_run"
STATUS_CHANGED = "status_changed"
ERROR = "error"
COMPLETED = "completed"
class TaskEventListener:
def handle(self, event: TaskEvent, task: "Task", payload: Optional[Any] = None):
pass
def handle_log(self, task: "Task", message: str):
pass
class ExecutionContext:
def __init__(self):
self._assets: Dict[str, Any] = {}
def put_asset(self, key: str, value: Any):
self._assets[key] = value
def get_asset(self, key: str, default: Any = None):
return self._assets.get(key, default)
def snapshot(self):
return dict(self._assets)
class Task(ABC):
def __init__(self, name: str):
self._name = name
# execution dependencies (DAG edges)
self._parents: List["Task"] = []
# structural parent in workflow tree (Composite hierarchy)
self._parent_task: Optional["Task"] = None
self._status: Status = Status.PENDING
self._listeners: List[TaskEventListener] = []
self._timestamps: Dict[str, datetime] = {}
@property
def name(self):
return self._name
@property
def parents(self):
return self._parents
def add_parent(self, parent: "Task"):
if parent not in self._parents:
self._parents.append(parent)
def set_parent_task(self, parent: "Task"):
self._parent_task = parent
# Events / Logging / Status
def add_listener(self, listener: TaskEventListener):
self._listeners.append(listener)
def _emit(self, event: TaskEvent, payload: Optional[Any] = None):
for listener in self._listeners:
listener.handle(event, self, payload)
def log(self, message: str):
for listener in self._listeners:
listener.handle_log(self, message)
def _set_status(self, new_status: Status):
old_status = self._status
self._status = new_status
if new_status == Status.RUNNING:
self._timestamps["start"] = datetime.now()
if new_status in (Status.COMPLETED, Status.FAILED, Status.STOPPED):
self._timestamps["end"] = datetime.now()
if old_status != new_status:
self._emit(TaskEvent.STATUS_CHANGED, {"from": old_status, "to": new_status})
def get_status(self):
return self._status
def get_timestamps(self):
return dict(self._timestamps)
# Abstract execution
@abstractmethod
def run(self, context: ExecutionContext):
pass
def __repr__(self):
return f"<Task {self.name}>"