"""页面期望状态与托管进程心跳,二者分别更新。""" from datetime import timedelta from sqlalchemy import inspect, select, update from app.core.exceptions import BadRequestError, ConflictError from app.models import TPlusRuntimeControl from app.services.authorization_service import require_permission from app.services.tplus import task_service from app.services.tplus.automation import local_now def overview(session, *, now=None): result = {"desired_state": "STOPPED", "actual_state": "OFFLINE", "worker_phase": "UNKNOWN", "heartbeat_at": None, "last_error": None, "host": None, "platform": None, "version": 0, "updated_by": None, "editable": False} if not inspect(session.connection()).has_table(TPlusRuntimeControl.__tablename__): return result row = session.scalar(select(TPlusRuntimeControl).where(TPlusRuntimeControl.id == 1) .execution_options(populate_existing=True)) if row is None: return result result.update({key: getattr(row, key) for key in result if key != "editable"}) result["editable"] = True if row.heartbeat_at is None or (now or local_now()) - row.heartbeat_at > timedelta(seconds=90): result["actual_state"] = "OFFLINE" result["worker_phase"] = "UNKNOWN" return result def save(session, payload, actor): require_permission(session, actor.user, "tplus:collect") if not inspect(session.connection()).has_table(TPlusRuntimeControl.__tablename__): raise BadRequestError("读取服务管理尚未升级,请联系维护人员") with task_service._audit(session, actor, "修改读取服务状态", payload.model_dump()): changed = session.execute(update(TPlusRuntimeControl).where( TPlusRuntimeControl.id == 1, TPlusRuntimeControl.version == payload.expected_version, ).values(desired_state=payload.desired_state, version=payload.expected_version + 1, updated_by=actor.user.id)) if changed.rowcount != 1: session.rollback() raise ConflictError() session.commit() return overview(session)