```
feat(feishu): 添加飞书入站事件inbox和混合数据库协调功能 - 实现飞书入站事件持久化inbox机制,支持状态管理、租约锁定和重试退避 - 添加混合数据库基线协调工具,确保平台PostgreSQL结构安全对齐 - 增加运行组件心跳检测和readiness就绪检查机制 - 实现app_ticket事件的安全轮换和验证处理 - 添加生产环境运行编排和fail-closed安全机制 - 支持webhook快速确认和长连接独立进程处理 - 完善个人数据擦除时的待处理事件清理功能 ```
This commit is contained in:
73
app/modules/observability/runtime.py
Normal file
73
app/modules/observability/runtime.py
Normal file
@@ -0,0 +1,73 @@
|
||||
import logging
|
||||
from os import getpid
|
||||
from socket import gethostname
|
||||
from threading import Event, Thread
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
from app.core.config import get_settings
|
||||
from app.core.constants import ActorValue
|
||||
from app.core.database import SessionLocal
|
||||
from app.modules.observability.constants import HeartbeatComponent
|
||||
from app.modules.observability.service import ObservabilityService
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def attach_api_heartbeat(app: FastAPI) -> None:
|
||||
"""Record API process liveness without coupling it to request traffic."""
|
||||
|
||||
interval_seconds = max(1, get_settings().heartbeat_interval_seconds)
|
||||
instance_id = f"{gethostname()}:{getpid()}"
|
||||
|
||||
@app.on_event("startup")
|
||||
def start_api_heartbeat() -> None:
|
||||
current_thread = getattr(app.state, "api_heartbeat_thread", None)
|
||||
if current_thread is not None and current_thread.is_alive():
|
||||
return
|
||||
|
||||
stop_event = Event()
|
||||
_record_api_heartbeat(instance_id)
|
||||
thread = Thread(
|
||||
target=_api_heartbeat_loop,
|
||||
args=(stop_event, instance_id, interval_seconds),
|
||||
name="api-heartbeat",
|
||||
daemon=True,
|
||||
)
|
||||
app.state.api_heartbeat_stop_event = stop_event
|
||||
app.state.api_heartbeat_thread = thread
|
||||
app.state.api_heartbeat_instance_id = instance_id
|
||||
thread.start()
|
||||
|
||||
@app.on_event("shutdown")
|
||||
def stop_api_heartbeat() -> None:
|
||||
stop_event = getattr(app.state, "api_heartbeat_stop_event", None)
|
||||
thread = getattr(app.state, "api_heartbeat_thread", None)
|
||||
if stop_event is not None:
|
||||
stop_event.set()
|
||||
if thread is not None:
|
||||
thread.join(timeout=1)
|
||||
|
||||
|
||||
def _api_heartbeat_loop(
|
||||
stop_event: Event,
|
||||
instance_id: str,
|
||||
interval_seconds: int,
|
||||
) -> None:
|
||||
while not stop_event.wait(max(1, interval_seconds)):
|
||||
_record_api_heartbeat(instance_id)
|
||||
|
||||
|
||||
def _record_api_heartbeat(instance_id: str) -> None:
|
||||
db = SessionLocal()
|
||||
try:
|
||||
ObservabilityService(db).record_heartbeat(
|
||||
component=HeartbeatComponent.API,
|
||||
instance_id=instance_id,
|
||||
actor=ActorValue.API,
|
||||
)
|
||||
except Exception:
|
||||
db.rollback()
|
||||
logger.exception("Failed to record API process heartbeat")
|
||||
finally:
|
||||
db.close()
|
||||
Reference in New Issue
Block a user