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.
Some checks failed
ci / validate (push) Has been cancelled

This commit is contained in:
2026-08-09 15:49:38 +00:00
parent 0c1c730f9b
commit 77da22255f

View File

@@ -1,53 +1,63 @@
import asyncio import asyncio
from datetime import UTC, datetime from uuid import UUID, uuid4
from uuid import UUID
from app.models import CurrentStatus, Monitor, MonitorCreate, MonitorUpdate from app.models import CurrentStatus, Monitor, MonitorCreate, MonitorUpdate, utc_now
class MonitorStore: class MonitorStore:
"""Concurrency-safe process-local state; all values cross the lock as copies."""
def __init__(self) -> None: def __init__(self) -> None:
self._items: dict[UUID, Monitor] = {}
self._lock = asyncio.Lock() self._lock = asyncio.Lock()
self._items: dict[UUID, Monitor] = {}
async def create(self, data: MonitorCreate) -> Monitor: async def create(self, value: MonitorCreate) -> Monitor:
monitor = Monitor(name=data.name, url=data.url) now = utc_now()
item = Monitor(
id=uuid4(), name=value.name, url=value.url, created_at=now, updated_at=now, revision=1
)
async with self._lock: async with self._lock:
self._items[monitor.id] = monitor self._items[item.id] = item
return monitor.model_copy(deep=True) return item.model_copy(deep=True)
async def list(self) -> list[Monitor]: async def list(self) -> list[Monitor]:
async with self._lock: async with self._lock:
return [item.model_copy(deep=True) for item in self._items.values()] 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 def get(self, monitor_id: UUID) -> Monitor | None:
async with self._lock: async with self._lock:
item = self._items.get(monitor_id) item = self._items.get(monitor_id)
return item.model_copy(deep=True) if item else None return item.model_copy(deep=True) if item else None
async def update(self, monitor_id: UUID, data: MonitorUpdate) -> Monitor | None: async def update(self, monitor_id: UUID, value: MonitorUpdate) -> Monitor | None:
changes = data.model_dump(exclude_unset=True, exclude_none=True)
async with self._lock: async with self._lock:
item = self._items.get(monitor_id) old = self._items.get(monitor_id)
if item is None: if old is None:
return None return None
updated = item.model_copy(update={**changes, "updated_at": datetime.now(UTC)}) changed_url = old.url != value.url
self._items[monitor_id] = updated item = old.model_copy(
return updated.model_copy(deep=True) update={
"name": value.name,
"url": value.url,
"updated_at": utc_now(),
"revision": old.revision + 1,
"current_status": None if changed_url else old.current_status,
}
)
self._items[monitor_id] = item
return item.model_copy(deep=True)
async def delete(self, monitor_id: UUID) -> bool: async def delete(self, monitor_id: UUID) -> bool:
async with self._lock: async with self._lock:
return self._items.pop(monitor_id, None) is not None return self._items.pop(monitor_id, None) is not None
async def set_status(self, monitor_id: UUID, status: CurrentStatus) -> Monitor | None: async def set_status_if_current(
self, monitor_id: UUID, revision: int, status: CurrentStatus
) -> bool:
async with self._lock: async with self._lock:
item = self._items.get(monitor_id) old = self._items.get(monitor_id)
if item is None: if old is None or old.revision != revision:
return None return False
updated = item.model_copy( self._items[monitor_id] = old.model_copy(
update={"current_status": status, "updated_at": datetime.now(UTC)} update={"current_status": status, "updated_at": utc_now()}
) )
self._items[monitor_id] = updated return True
return updated.model_copy(deep=True)