feat: 添加数据库迁移脚本并更新Dockerfile配置 - 在Dockerfile中添加alembic配置文件和目录的复制指令 - 更新alembic/env.py注册新的模块模型:events、workflows、writebacks - 生成完整的初始数据库schema迁移脚本,包含以下表: - approval_requests, attendance_records, audit_logs, domain_events - expenses, feishu_event_receipts, fund_accounts, legacy_sync_runs - official_writeback_runs, performance_metrics, policies, procurements - projects, report_push_runs, risk_event_actions, risk_events - standards, suppliers, work_reports, work_tasks, workflow_actions - workflow_instances等21个数据表结构定义 - 在API路由器中添加新模块的路由:events、workflows、writebacks、observability ```
115 lines
4.3 KiB
Python
115 lines
4.3 KiB
Python
from typing import Any
|
|
|
|
from sqlalchemy import text
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.core.config import get_settings
|
|
from app.modules.events.constants import EventStatus
|
|
from app.modules.events.service import EventService
|
|
from app.modules.observability.constants import (
|
|
ObservabilityKey,
|
|
ObservabilityMetricKey,
|
|
ObservabilityStatus,
|
|
)
|
|
from app.modules.workflows.constants import WorkflowStatus
|
|
from app.modules.workflows.service import WorkflowService
|
|
from app.modules.writebacks.constants import WritebackStatus
|
|
from app.modules.writebacks.service import WritebackService
|
|
|
|
|
|
class ObservabilityService:
|
|
"""Build health, readiness, and JSON metrics for V3 operations."""
|
|
|
|
def __init__(self, db: Session):
|
|
self.db = db
|
|
|
|
def live(self) -> dict[str, str]:
|
|
return {ObservabilityKey.STATUS: ObservabilityStatus.OK}
|
|
|
|
def ready(self) -> dict[str, Any]:
|
|
checks = {
|
|
ObservabilityKey.DATABASE: self._database_check(),
|
|
ObservabilityKey.REDIS: self._redis_check(),
|
|
ObservabilityKey.EVENTS: self._events_check(),
|
|
ObservabilityKey.WORKFLOWS: self._workflows_check(),
|
|
ObservabilityKey.WRITEBACKS: self._writebacks_check(),
|
|
}
|
|
degraded = any(
|
|
item[ObservabilityKey.STATUS]
|
|
in {ObservabilityStatus.DEGRADED, ObservabilityStatus.ERROR}
|
|
for item in checks.values()
|
|
)
|
|
return {
|
|
ObservabilityKey.STATUS: (
|
|
ObservabilityStatus.DEGRADED if degraded else ObservabilityStatus.OK
|
|
),
|
|
ObservabilityKey.CHECKS: checks,
|
|
}
|
|
|
|
def metrics(self) -> dict[str, Any]:
|
|
return {
|
|
ObservabilityKey.METRICS: {
|
|
ObservabilityKey.EVENTS: EventService(self.db).count_by_status(),
|
|
ObservabilityKey.WORKFLOWS: WorkflowService(self.db).count_by_status(),
|
|
ObservabilityKey.WRITEBACKS: WritebackService(self.db).count_by_status(),
|
|
}
|
|
}
|
|
|
|
def _database_check(self) -> dict[str, Any]:
|
|
try:
|
|
self.db.execute(text("select 1")).scalar()
|
|
except Exception as exc:
|
|
return {
|
|
ObservabilityKey.STATUS: ObservabilityStatus.ERROR,
|
|
ObservabilityMetricKey.ERROR: str(exc),
|
|
}
|
|
return {ObservabilityKey.STATUS: ObservabilityStatus.OK}
|
|
|
|
def _redis_check(self) -> dict[str, Any]:
|
|
settings = get_settings()
|
|
if not settings.task_queue_enabled:
|
|
return {ObservabilityKey.STATUS: ObservabilityStatus.SKIPPED}
|
|
try:
|
|
from redis import Redis
|
|
|
|
Redis.from_url(settings.redis_url, socket_connect_timeout=1).ping()
|
|
except Exception as exc:
|
|
return {
|
|
ObservabilityKey.STATUS: ObservabilityStatus.DEGRADED,
|
|
ObservabilityMetricKey.ERROR: str(exc),
|
|
}
|
|
return {ObservabilityKey.STATUS: ObservabilityStatus.OK}
|
|
|
|
def _events_check(self) -> dict[str, Any]:
|
|
counts = EventService(self.db).count_by_status()
|
|
failed = counts.get(EventStatus.FAILED, 0)
|
|
return {
|
|
ObservabilityKey.STATUS: (
|
|
ObservabilityStatus.DEGRADED if failed else ObservabilityStatus.OK
|
|
),
|
|
ObservabilityMetricKey.PENDING: counts.get(EventStatus.PENDING, 0),
|
|
ObservabilityMetricKey.FAILED: failed,
|
|
}
|
|
|
|
def _workflows_check(self) -> dict[str, Any]:
|
|
counts = WorkflowService(self.db).count_by_status()
|
|
failed = counts.get(WorkflowStatus.FAILED, 0)
|
|
return {
|
|
ObservabilityKey.STATUS: (
|
|
ObservabilityStatus.DEGRADED if failed else ObservabilityStatus.OK
|
|
),
|
|
ObservabilityMetricKey.RUNNING: counts.get(WorkflowStatus.RUNNING, 0),
|
|
ObservabilityMetricKey.FAILED: failed,
|
|
}
|
|
|
|
def _writebacks_check(self) -> dict[str, Any]:
|
|
counts = WritebackService(self.db).count_by_status()
|
|
failed = counts.get(WritebackStatus.FAILED, 0)
|
|
return {
|
|
ObservabilityKey.STATUS: (
|
|
ObservabilityStatus.DEGRADED if failed else ObservabilityStatus.OK
|
|
),
|
|
ObservabilityMetricKey.DISABLED: counts.get(WritebackStatus.DISABLED, 0),
|
|
ObservabilityMetricKey.FAILED: failed,
|
|
}
|