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 / quality (push) Has been cancelled
ci / container (push) Has been cancelled

This commit is contained in:
2026-08-09 16:09:53 +00:00
parent 3200e488a8
commit 27d10998b7

View File

@@ -1,57 +1,61 @@
from datetime import datetime, timezone from datetime import datetime, timezone
from enum import Enum from enum import Enum
from uuid import UUID from uuid import UUID, uuid4
from pydantic import AnyHttpUrl, BaseModel, ConfigDict, Field, field_validator from pydantic import BaseModel, ConfigDict, Field, HttpUrl
def utc_now() -> datetime: def now_utc() -> datetime:
return datetime.now(timezone.utc) return datetime.now(timezone.utc)
class MonitorState(str, Enum): class MonitorState(str, Enum):
UNKNOWN = "unknown" unknown = "unknown"
UP = "up" up = "up"
DOWN = "down" down = "down"
ERROR = "error"
class CurrentStatus(BaseModel): class MonitorCreate(BaseModel):
state: MonitorState = MonitorState.UNKNOWN
checked_at: datetime | None = None
latency_ms: float | None = Field(default=None, ge=0)
http_status: int | None = Field(default=None, ge=100, le=599)
error: str | None = Field(default=None, max_length=500)
class MonitorFields(BaseModel):
model_config = ConfigDict(str_strip_whitespace=True)
name: str = Field(min_length=1, max_length=100) name: str = Field(min_length=1, max_length=100)
target_url: AnyHttpUrl url: HttpUrl
timeout_seconds: float | None = Field(None, gt=0, le=60)
@field_validator("target_url")
@classmethod
def reject_credentials(cls, value: AnyHttpUrl) -> AnyHttpUrl:
if value.username is not None or value.password is not None:
raise ValueError("URL credentials are not allowed")
return value
class MonitorCreate(MonitorFields): class MonitorUpdate(BaseModel):
name: str | None = Field(None, min_length=1, max_length=100)
url: HttpUrl | None = None
timeout_seconds: float | None = Field(None, gt=0, le=60)
class MonitorStatus(BaseModel):
state: MonitorState = MonitorState.unknown
checked_at: datetime | None = None
http_status: int | None = None
latency_ms: float | None = None
error: str | None = None
class Monitor(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: UUID = Field(default_factory=uuid4)
name: str
url: HttpUrl
timeout_seconds: float
created_at: datetime = Field(default_factory=now_utc)
updated_at: datetime = Field(default_factory=now_utc)
status: MonitorStatus = Field(default_factory=MonitorStatus)
class CheckResult(MonitorStatus):
pass pass
class MonitorUpdate(MonitorFields): class ErrorBody(BaseModel):
pass code: str
message: str
details: list[dict[str, object]] | None = None
class Monitor(MonitorFields): class ErrorResponse(BaseModel):
id: UUID error: ErrorBody
created_at: datetime
updated_at: datetime
current_status: CurrentStatus
class Health(BaseModel):
status: str