feat(feishu): 添加飞书入站事件inbox和混合数据库协调功能

- 实现飞书入站事件持久化inbox机制,支持状态管理、租约锁定和重试退避
- 添加混合数据库基线协调工具,确保平台PostgreSQL结构安全对齐
- 增加运行组件心跳检测和readiness就绪检查机制
- 实现app_ticket事件的安全轮换和验证处理
- 添加生产环境运行编排和fail-closed安全机制
- 支持webhook快速确认和长连接独立进程处理
- 完善个人数据擦除时的待处理事件清理功能
```
This commit is contained in:
2026-07-27 17:14:37 +08:00
parent d7db84571d
commit eb8267ed18
61 changed files with 8703 additions and 183 deletions

View File

@@ -1,10 +1,14 @@
from datetime import datetime
from sqlalchemy import DateTime, Integer, String, Text
from sqlalchemy import JSON, Boolean, DateTime, Integer, String, Text, true
from sqlalchemy.orm import Mapped, mapped_column
from app.core.database import Base
from app.core.utils.time import utc_now
from app.modules.feishu.constants import (
FEISHU_INBOUND_MAX_ATTEMPTS,
FeishuInboundStatus,
)
class FeishuEventReceipt(Base):
@@ -15,7 +19,79 @@ class FeishuEventReceipt(Base):
source: Mapped[str] = mapped_column(String(64), index=True)
event_id: Mapped[str | None] = mapped_column(String(128), nullable=True, index=True)
message_id: Mapped[str | None] = mapped_column(String(128), nullable=True, index=True)
event_type: Mapped[str | None] = mapped_column(String(128), nullable=True, index=True)
payload: Mapped[dict | None] = mapped_column(JSON, nullable=True)
auto_reply: Mapped[bool] = mapped_column(
Boolean,
default=True,
server_default=true(),
)
status: Mapped[str] = mapped_column(
String(32),
default=FeishuInboundStatus.PENDING,
server_default=FeishuInboundStatus.PENDING,
index=True,
)
attempt_count: Mapped[int] = mapped_column(Integer, default=0, server_default="0")
max_attempts: Mapped[int] = mapped_column(
Integer,
default=FEISHU_INBOUND_MAX_ATTEMPTS,
server_default=str(FEISHU_INBOUND_MAX_ATTEMPTS),
)
last_error: Mapped[str | None] = mapped_column(Text, nullable=True)
next_attempt_at: Mapped[datetime | None] = mapped_column(
DateTime,
nullable=True,
index=True,
)
locked_until: Mapped[datetime | None] = mapped_column(
DateTime,
nullable=True,
index=True,
)
locked_by: Mapped[str | None] = mapped_column(
String(128),
nullable=True,
index=True,
)
received_at: Mapped[datetime] = mapped_column(DateTime, default=utc_now, index=True)
processed_at: Mapped[datetime | None] = mapped_column(
DateTime,
nullable=True,
index=True,
)
reply_payload: Mapped[dict | None] = mapped_column(JSON, nullable=True)
reply_status: Mapped[str | None] = mapped_column(
String(32),
nullable=True,
index=True,
)
reply_attempt_count: Mapped[int] = mapped_column(
Integer,
default=0,
server_default="0",
)
reply_last_error: Mapped[str | None] = mapped_column(Text, nullable=True)
reply_next_attempt_at: Mapped[datetime | None] = mapped_column(
DateTime,
nullable=True,
index=True,
)
reply_locked_until: Mapped[datetime | None] = mapped_column(
DateTime,
nullable=True,
index=True,
)
reply_locked_by: Mapped[str | None] = mapped_column(
String(128),
nullable=True,
index=True,
)
reply_sent_at: Mapped[datetime | None] = mapped_column(
DateTime,
nullable=True,
index=True,
)
class FeishuAppTicket(Base):