From 53103d12c15d37ff1a0e95bb488bcc0919ff9561 Mon Sep 17 00:00:00 2001 From: demo-bot Date: Sun, 9 Aug 2026 15:35:35 +0000 Subject: [PATCH] decomposer: generate deliverable files for Define the service contract and project architecture for the FastAPI endpoint monitoring service.; Implement the typed monitor CRUD API and concurrency-safe in-memory state according to the service design.; Implement secure on-demand endpoint checks with status updates, latency measurement, robust error handling, and redacted structured logs.; Add operational API endpoints and environment-driven runtime configuration to the monitoring service.; Create automated tests for the monitoring service.; Package the service with Docker and developer documentation.; Validate the complete project. --- app/store.py | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 app/store.py diff --git a/app/store.py b/app/store.py new file mode 100644 index 0000000..8a1b1e0 --- /dev/null +++ b/app/store.py @@ -0,0 +1,68 @@ +import asyncio +from uuid import UUID, uuid4 + +from app.models import CurrentStatus, Monitor, MonitorCreate, MonitorUpdate, utcnow + + +class MonitorStore: + """Lock-protected process-local storage returning defensive copies.""" + + def __init__(self) -> None: + self._lock = asyncio.Lock() + self._items: dict[UUID, Monitor] = {} + self._revisions: dict[UUID, int] = {} + + async def create(self, data: MonitorCreate) -> Monitor: + now = utcnow() + item = Monitor(id=uuid4(), name=data.name, url=data.url, created_at=now, + updated_at=now, current_status=CurrentStatus()) + async with self._lock: + self._items[item.id] = item + self._revisions[item.id] = 0 + return item.model_copy(deep=True) + + async def list(self) -> list[Monitor]: + async with self._lock: + values = sorted(self._items.values(), key=lambda item: item.created_at) + return [item.model_copy(deep=True) for item in values] + + async def get(self, monitor_id: UUID) -> Monitor | None: + async with self._lock: + item = self._items.get(monitor_id) + return item.model_copy(deep=True) if item else None + + async def snapshot(self, monitor_id: UUID) -> tuple[Monitor, int] | None: + async with self._lock: + item = self._items.get(monitor_id) + if item is None: + return None + return item.model_copy(deep=True), self._revisions[monitor_id] + + async def update(self, monitor_id: UUID, data: MonitorUpdate) -> Monitor | None: + async with self._lock: + item = self._items.get(monitor_id) + if item is None: + return None + changes = data.model_dump(exclude_none=True) + changes["updated_at"] = utcnow() + updated = item.model_copy(update=changes, deep=True) + self._items[monitor_id] = updated + self._revisions[monitor_id] += 1 + return updated.model_copy(deep=True) + + async def delete(self, monitor_id: UUID) -> bool: + async with self._lock: + existed = self._items.pop(monitor_id, None) is not None + self._revisions.pop(monitor_id, None) + return existed + + async def record_status(self, monitor_id: UUID, revision: int, + status: CurrentStatus) -> Monitor | None: + async with self._lock: + item = self._items.get(monitor_id) + if item is None or self._revisions[monitor_id] != revision: + return None + updated = item.model_copy(update={"current_status": status, + "updated_at": utcnow()}, deep=True) + self._items[monitor_id] = updated + return updated.model_copy(deep=True)