137 lines
4.5 KiB
Python
137 lines
4.5 KiB
Python
"""Repair orchestration for signal source repair service."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from .errors import SignalSourceRepairMissingSignalError
|
|
from .shared import ProactiveSignalCaptureService
|
|
|
|
|
|
class SignalSourceRepairFlowMixin:
|
|
"""Runs single/batch repair orchestration."""
|
|
|
|
async def _repair_single_registry(
|
|
self,
|
|
*,
|
|
capture_service: ProactiveSignalCaptureService,
|
|
tenant_id: int,
|
|
project_id: int,
|
|
registry_id: int,
|
|
sender: str,
|
|
timeout_seconds: int,
|
|
) -> dict[str, object]:
|
|
row = await self._load_registry(
|
|
tenant_id=tenant_id,
|
|
project_id=project_id,
|
|
registry_id=registry_id,
|
|
)
|
|
if row is None:
|
|
return {"registry_id": int(registry_id), "status": "not_found"}
|
|
if row.signal_id is not None:
|
|
return self._build_item_result(
|
|
row=row,
|
|
signal_id=self._safe_int(row.signal_id),
|
|
capture_status="already_linked",
|
|
work_item_id=None,
|
|
route_status="",
|
|
)
|
|
|
|
reusable_signal_id = await self._find_reusable_signal_id(
|
|
tenant_id=tenant_id,
|
|
project_id=project_id,
|
|
row=row,
|
|
)
|
|
if reusable_signal_id is not None:
|
|
await self._persist_registry_link(
|
|
tenant_id=tenant_id,
|
|
project_id=project_id,
|
|
row=row,
|
|
signal_id=int(reusable_signal_id),
|
|
capture_status="relinked",
|
|
)
|
|
return self._build_item_result(
|
|
row=row,
|
|
signal_id=int(reusable_signal_id),
|
|
capture_status="relinked",
|
|
work_item_id=None,
|
|
route_status="",
|
|
)
|
|
|
|
capture_result = await self._capture_registry(
|
|
capture_service=capture_service,
|
|
tenant_id=tenant_id,
|
|
project_id=project_id,
|
|
sender=sender,
|
|
row=row,
|
|
stage="base",
|
|
timeout_seconds=timeout_seconds,
|
|
)
|
|
signal_id = self._extract_signal_id(capture_result)
|
|
if signal_id is None:
|
|
capture_result = await self._capture_registry(
|
|
capture_service=capture_service,
|
|
tenant_id=tenant_id,
|
|
project_id=project_id,
|
|
sender=sender,
|
|
row=row,
|
|
stage="explicit",
|
|
timeout_seconds=timeout_seconds,
|
|
)
|
|
signal_id = self._extract_signal_id(capture_result)
|
|
|
|
if signal_id is None:
|
|
signal_id = await self._find_reusable_signal_id(
|
|
tenant_id=tenant_id,
|
|
project_id=project_id,
|
|
row=row,
|
|
)
|
|
if signal_id is None:
|
|
raise SignalSourceRepairMissingSignalError(
|
|
registry_id=int(row.id),
|
|
project_id=int(project_id),
|
|
status=str(capture_result.get("status") or ""),
|
|
)
|
|
|
|
capture_status = str(capture_result.get("status") or "captured")
|
|
await self._persist_registry_link(
|
|
tenant_id=tenant_id,
|
|
project_id=project_id,
|
|
row=row,
|
|
signal_id=int(signal_id),
|
|
capture_status=capture_status,
|
|
)
|
|
return self._build_item_result(
|
|
row=row,
|
|
signal_id=int(signal_id),
|
|
capture_status=capture_status,
|
|
work_item_id=self._safe_int(capture_result.get("work_item_id")),
|
|
route_status=self._extract_route_status(capture_result),
|
|
)
|
|
|
|
async def repair_registries(
|
|
self,
|
|
*,
|
|
tenant_id: int,
|
|
project_id: int,
|
|
registry_ids: list[int],
|
|
sender: str,
|
|
) -> list[dict[str, object]]:
|
|
capture_service = ProactiveSignalCaptureService(self.db)
|
|
timeout_seconds = self._resolve_timeout_seconds()
|
|
results: list[dict[str, object]] = []
|
|
try:
|
|
for registry_id in registry_ids:
|
|
item = await self._repair_single_registry(
|
|
capture_service=capture_service,
|
|
tenant_id=tenant_id,
|
|
project_id=project_id,
|
|
registry_id=int(registry_id),
|
|
sender=sender,
|
|
timeout_seconds=timeout_seconds,
|
|
)
|
|
results.append(item)
|
|
await self.db.commit()
|
|
except Exception:
|
|
await self.db.rollback()
|
|
raise
|
|
return results
|