Files
EchoChat/backend/go-service/config/config.dev.yaml
bujinyuan 3b83c79036 feat(phase2e-2): 落地会议生命周期状态机 + Router 幂等双层防御(Task 8)
核心交付:
- 新建 MeetingLifecycleService(6 钩子 + sync.Map 本地 timer + Redis key 双保险 + RescheduleFromRedis)
- 新建 MeetingCleanupTask(启动重建 timer + 每 N 秒扫 host_grace/empty_ttl 兜底 + 4h stale active 回收)
- MediaOrchestrator 新增 ResolveRouterID;HTTPMediaOrchestrator.CreateRouter 入口 sync.Map 幂等防御
- 业务层 JoinRoom 移除 CreateRouter 调用改走 CancelEmptyTTL + ResolveRouterID;LeaveRoom 空房分支改调 OnAllMembersLeft 不再立即销毁
- MeetingSignalService 新增 OnWSDisconnect 实现 ws.MeetingDisconnectHook;OnRoomJoin 追加 host 重连钩子
- ws.handler 定义 MeetingDisconnectHook 接口 + SetMeetingDisconnectHook,解耦 ws→meeting 反向依赖
- config 新增 MeetingConfig{HostGrace=120, EmptyRoomTTL=300, CleanupInterval=30, StaleRoomHours=4}

关键设计决策:
- Redis key TTL = 业务时长 + max(CleanupIntervalSeconds*2, 30s) buffer:避免本地 timer 与
  Redis 自动过期同步到期导致 DEL 返回 0 被误判为"已被其他路径处理"而跳过业务逻辑
- Router 幂等双层防御(决策 q2_router_dedup=a2_both):业务层不重复调 + HTTP 层 sync.Map 命中直接返回
- 普通成员 WS 断开仅清 media 资源不动 participant 表(决策 q1_nonhost_disconnect=a1_keep_current)

E2E 验证:docs/verify/meeting_t8_verify.mjs PASS=20 FAIL=0,覆盖 5 场景:
- S1 host 宽限期过期自动转让(meeting.host.changed + DB host_id 更新)
- S2 宽限期内重连保留身份
- S3 empty_ttl 期内新成员加入复活房间
- S4 empty_ttl 过期 → 房间 Ended + 新 join 被拒
- S5 CreateRoom +1 Router / JoinRoom 不再创建新 Router(通过 media-server /internal/info stats.routers 断言)

media-server:/internal/info 响应追加 stats.routers + routers[] 供 E2E 断言 Router 幂等

文档同步:
- docs/progress/CURRENT_STATUS.md 头部 + 新增 Task 8 交付条目
- docs/plans/2026-04-21-phase2e-2-implementation.plan.md Task 8 标记完成 + 实际产出/决策/验证
- docs/api/frontend/meeting.md 补充 host.changed.auto_reason / room.ended.reason=system_error / 空房 TTL 复活语义 + Task 8 验证记录
- docs/architecture/system-architecture.md meeting 模块职责补充"会议生命周期状态机"
- .cursor/rules/project-context.mdc 追加 Task 8 条目并更新 Phase 2e-2 进度(Task 0-8 )

Made-with: Cursor
2026-04-21 18:21:04 +08:00

74 lines
3.9 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ============================================================
# EchoChat 开发环境配置
# 环境变量覆盖规则ECHOCHAT_{节}_{字段} 如 ECHOCHAT_SERVER_PORT=9090
# ============================================================
# HTTP 服务配置
server:
port: 8085 # 服务监听端口
mode: debug # 运行模式debug开发/ release生产
# PostgreSQL 数据库配置
database:
host: localhost # 数据库地址
port: 5432 # 数据库端口
user: echochat # 数据库用户名
password: echochat_dev_2026 # 数据库密码
dbname: echochat # 数据库名称
sslmode: disable # SSL 模式disable开发/ require生产
max_idle_conns: 10 # 连接池最大空闲连接数
max_open_conns: 100 # 连接池最大打开连接数
# Redis 配置
redis:
host: localhost # Redis 地址
port: 6379 # Redis 端口
password: "" # Redis 密码,开发环境为空
db: 0 # Redis 数据库编号0-15
# JWT 认证配置
jwt:
secret: echochat-dev-jwt-secret-2026-please-change-in-production # JWT 签名密钥,生产环境必须更换
access_expire_min: 120 # Access Token 有效期(分钟),即 2 小时
refresh_expire_day: 7 # Refresh Token 有效期(天),即 7 天
issuer: echochat # JWT 签发者标识
# 日志配置
log:
level: debug # 最低输出级别debug / info / warn / error
format: text # 控制台输出格式text彩色可读/ json结构化
output_path: stdout # 控制台输出目标(保留字段,始终输出到 stdout
file:
enable: true # 是否启用日志文件输出true 时同时写入控制台和文件)
dir: logs # 日志文件存放目录(相对于 go-service 工作目录)
max_size: 50 # 单个日志文件最大大小MB超过后自动切割产生新文件
max_backups: 10 # 保留的旧日志归档文件最大数量,超出的自动删除
max_age: 30 # 旧日志归档文件保留天数,超过天数的自动删除
compress: false # 是否对归档的旧日志文件进行 gzip 压缩(生产环境建议 true
# MinIO 对象存储配置
minio:
endpoint: "localhost:9000" # MinIO 服务地址
access_key: "echochat" # 访问密钥(与 docker-compose 中的 MINIO_ROOT_USER 一致)
secret_key: "echochat123456" # 密钥(与 docker-compose 中的 MINIO_ROOT_PASSWORD 一致)
bucket: "echochat" # 存储桶名称
use_ssl: false # 开发环境不使用 HTTPS
# Node media-server 接入配置Phase 2e-2 Task 7 HTTPMediaOrchestrator
# 对应 media-server/.env 的 MEDIA_INTERNAL_TOKEN + HTTP_PORT默认 3300
# 生产环境通过环境变量 ECHOCHAT_MEDIA_SERVER_INTERNAL_TOKEN 覆盖
media_server:
base_url: "http://localhost:3300" # media-server 基础 URL不含末尾斜杠
internal_token: "dev-token-abcdef1234567890" # 与 media-server/.env MEDIA_INTERNAL_TOKEN 一致(开发环境)
timeout_ms: 5000 # 创建类接口超时(毫秒)
close_timeout_ms: 2000 # 关闭类接口超时(毫秒)
close_retry: 2 # 关闭类接口失败重试次数(指数退避 200/500ms
# 会议模块生命周期参数Phase 2e-2 Task 8 会议状态机)
# E2E 测试可通过环境变量 ECHOCHAT_MEETING_HOST_GRACE_SECONDS 等覆盖为更短值以加速触发
meeting:
host_grace_seconds: 120 # 主持人掉线宽限期(秒),期间保留 host 身份
empty_room_ttl_seconds: 300 # 空房自动销毁 TTL期间有人加入可复活
cleanup_interval_seconds: 30 # 兜底扫描周期(秒),定时任务检查过期 grace/empty_ttl key
stale_room_hours: 4 # 活跃超过此小时且无活跃成员视为 stale强制结束