"""Answer Execution Core and Pipeline Workload ports from Workload Portfolio's saved records.""" from collections.abc import Callable from psycopg import Error as DatabaseError from metallo.adaptors.postgres import Database from metallo.contexts.execution_core.application.launch_acceptance import ( LaunchWorkload, WorkloadLookupUnavailable as LaunchLookupUnavailable, ) from metallo.contexts.execution_core.application.planning_inputs import WorkloadRevision from metallo.contexts.execution_core.application.repository_runs import LaunchedAction, NamesUnavailable from metallo.contexts.pipeline_coordination.application.ports import ( PipelineWorkloadRevision, WorkloadLookupUnavailable as PipelineLookupUnavailable, ) from metallo.contexts.workload_portfolio.adaptors.postgres import saved_workloads from metallo.contexts.workload_portfolio.application.saved import SavedWorkloads from metallo.contexts.workload_portfolio.domain.workload import Workload, WorkloadRevision as SavedRevision from metallo.foundation.domain import CorruptState, record, text def _read[T](read: Callable[[], T], unavailable: type[RuntimeError]) -> T: try: return read() except (CorruptState, DatabaseError) as error: # Corrupt or unreachable owner state is retryable evidence failure, never a business answer. raise unavailable("Workload Portfolio evidence is unavailable") from error class LaunchWorkloads: """Execution Core launch acceptance: current state, version and revision.""" def __init__(self, workloads: SavedWorkloads) -> None: self.workloads = workloads def get_workload(self, workload_id: str) -> LaunchWorkload | None: saved = _read(lambda: self.workloads.get(workload_id), LaunchLookupUnavailable) if saved is None: return None return LaunchWorkload(saved.id, saved.project_id, saved.version, saved.current_revision.number, saved.state) def _exact(workloads: SavedWorkloads, workload_id: str, number: int, unavailable: type[RuntimeError]) -> tuple[Workload, SavedRevision] | None: saved = _read(lambda: workloads.get(workload_id), unavailable) # Retirement stops new launches; already accepted work still reads its exact revision. revision = None if saved is None else saved.revision(number) return None if saved is None or revision is None else (saved, revision) class PlanningRevisions: """Execution Core planning: the exact immutable specification and required inputs.""" def __init__(self, workloads: SavedWorkloads) -> None: self.workloads = workloads def get_revision(self, workload_id: str, revision: int) -> WorkloadRevision | None: found = _exact(self.workloads, workload_id, revision, LaunchLookupUnavailable) if found is None: return None saved, value = found return WorkloadRevision(saved.id, saved.project_id, value.number, value.specification, value.required_inputs) class PipelineRevisions: """Pipeline Coordination: the exact revision's Project and execution profile.""" def __init__(self, workloads: SavedWorkloads) -> None: self.workloads = workloads def get_revision(self, workload_id: str, revision: int) -> PipelineWorkloadRevision | None: found = _exact(self.workloads, workload_id, revision, PipelineLookupUnavailable) if found is None: return None saved, value = found return PipelineWorkloadRevision(saved.id, saved.project_id, value.number, value.family, value.service_kind) class PipelineActionNames: """Pipeline Coordination's step views: the name of the action each step's Workload runs.""" def __init__(self, workloads: SavedWorkloads) -> None: self.workloads = workloads def name(self, workload_id: str) -> str | None: saved = _read(lambda: self.workloads.get(workload_id), PipelineLookupUnavailable) return None if saved is None else saved.display_name class RunActionNames: """Execution Core Run views: the name of the action each Run's Workload runs.""" def __init__(self, workloads: SavedWorkloads) -> None: self.workloads = workloads def name(self, workload_id: str) -> str | None: saved = _read(lambda: self.workloads.get(workload_id), NamesUnavailable) return None if saved is None else saved.display_name def launched(self, workload_id: str, revision: int) -> LaunchedAction | None: """A launch's action before its Run exists: the saved revision's family and repository (#766).""" saved = _read(lambda: self.workloads.get(workload_id), NamesUnavailable) if saved is None or not 1 <= revision <= len(saved.revisions): return None try: intent = record(saved.revisions[revision - 1].specification["intent"]) repository = record(intent["repository"])["repositoryId"] if "repository" in intent else None return LaunchedAction(saved.display_name, text(intent["family"]), None if repository is None else text(repository)) except (KeyError, TypeError, ValueError) as error: raise NamesUnavailable("A saved Workload revision has no readable action") from error def workload_owners(database: Database) -> tuple[LaunchWorkloads, PlanningRevisions, PipelineRevisions]: workloads = saved_workloads(database) return LaunchWorkloads(workloads), PlanningRevisions(workloads), PipelineRevisions(workloads)