fix(meeting): Task 16 修复 code-reviewer 审计 P1 八项
按 docs/reviews/2026-04-23-phase2e-2-code-review.md 清单落地 P1 批次: - P1-1 主持人转让原子性:MeetingParticipantDAO.TransferHost 内部事务 合并 meeting_rooms.host_id 更新,service/lifecycle 移除冗余 UpdateHost - P1-2 ListChatMessages / ListMyMeetings 回归 DAO:新增 MeetingChatDAO.ListByRoomBefore 反向游标,service 移除 s.db 直查 - P1-3 ListMyMeetings N+1 放大优化:新增 MeetingParticipantDAO.ListJoinedRoomsByUser JOIN + DISTINCT 单次 SQL - P1-4 EndRoom 行锁 + 事务:s.db.Transaction 包裹 SELECT FOR UPDATE → 快照 → MarkEnded → LeaveAllActive;DAO 补 WithTx(*gorm.DB) 和 GetByIDForUpdate - P1-5 后台 goroutine trace_id 保留:新增 logs.DetachContext(ctx); 替换 meeting_service / meeting_signal_service 共 10 处 context.Background(); meeting_ws_handler 每条 WS 消息分配独立 trace_id - P1-6 _broadcastSelfState 重试:最多 2 次指数退避(700ms→2100ms), 检测 localAudioEnabled/localVideoEnabled 已被后续动作覆盖时放弃旧 patch - P1-7 HandleHostGraceExpired / HandleEmptyRoomExpired 处理锁: 独立 host_grace_handling:<code> / empty_ttl_handling:<code> SETNX + 60s TTL, 消除 Redis 自然过期 + 本地 timer 到点 + DEL 返回 0 的盲区 - P1-8 pushExistingRoomState 同步化:OnRoomJoin 返回前完成补推, 消除与 REST member.joined 并行造成的前端状态闪烁 并附带修复 .gitignore 中 logs/ 规则误伤 pkg/logs/ 代码目录的历史遗留问题, 将 logger.go / trace.go 正式纳入版本控制。 验证:backend go build + go vet 通过;frontend npm run build:h5 通过。 Made-with: Cursor
This commit is contained in:
@@ -58,6 +58,15 @@ type simpleRoomPayload struct {
|
||||
RoomCode string `json:"room_code"`
|
||||
}
|
||||
|
||||
// newEventContext 为每个 WS 事件生成独立 ctx(携带新 trace_id)
|
||||
// Task 16 P1-5:WS 层无 HTTP 中间件注入 trace_id,旧版 handler 一律 context.Background(),
|
||||
// 导致 signalSvc → Redis / DB / broadcaster 的整条链路日志无法通过 trace_id 串联。
|
||||
// 现改为每条 WS 消息生成独立 UUID 作为 trace_id,相当于 RPC 语义;配合 service 层
|
||||
// logs.DetachContext 用于后台 goroutine,可形成完整"WS 消息 → 业务处理 → 异步广播"的日志链路。
|
||||
func (h *MeetingWSHandler) newEventContext() context.Context {
|
||||
return logs.WithTraceID(context.Background(), logs.GenerateTraceID())
|
||||
}
|
||||
|
||||
// sendACK 统一发送 ACK 响应
|
||||
func (h *MeetingWSHandler) sendACK(client *ws.Client, msg *ws.Message, code int, message string, data interface{}) {
|
||||
resp := ws.NewResponse(msg.Event, msg.Seq, code, message, data)
|
||||
@@ -91,7 +100,7 @@ func (h *MeetingWSHandler) handleRoomJoin(client *ws.Client, msg *ws.Message) {
|
||||
if !h.unmarshal(client, msg, &payload) {
|
||||
return
|
||||
}
|
||||
if err := h.signalSvc.OnRoomJoin(context.Background(), client.UserID, payload.RoomCode); err != nil {
|
||||
if err := h.signalSvc.OnRoomJoin(h.newEventContext(), client.UserID, payload.RoomCode); err != nil {
|
||||
h.sendACK(client, msg, -1, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
@@ -104,7 +113,7 @@ func (h *MeetingWSHandler) handleRoomLeave(client *ws.Client, msg *ws.Message) {
|
||||
if !h.unmarshal(client, msg, &payload) {
|
||||
return
|
||||
}
|
||||
if err := h.signalSvc.OnRoomLeave(context.Background(), client.UserID, payload.RoomCode); err != nil {
|
||||
if err := h.signalSvc.OnRoomLeave(h.newEventContext(), client.UserID, payload.RoomCode); err != nil {
|
||||
h.sendACK(client, msg, -1, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
@@ -119,7 +128,7 @@ func (h *MeetingWSHandler) handleMemberStateChange(client *ws.Client, msg *ws.Me
|
||||
if !h.unmarshal(client, msg, &payload) {
|
||||
return
|
||||
}
|
||||
if err := h.signalSvc.OnMemberStateChanged(context.Background(), client.UserID, &payload); err != nil {
|
||||
if err := h.signalSvc.OnMemberStateChanged(h.newEventContext(), client.UserID, &payload); err != nil {
|
||||
h.sendACK(client, msg, -1, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
@@ -134,7 +143,7 @@ func (h *MeetingWSHandler) handleTransportCreate(client *ws.Client, msg *ws.Mess
|
||||
if !h.unmarshal(client, msg, &payload) {
|
||||
return
|
||||
}
|
||||
info, err := h.signalSvc.OnTransportCreate(context.Background(), client.UserID, &payload)
|
||||
info, err := h.signalSvc.OnTransportCreate(h.newEventContext(), client.UserID, &payload)
|
||||
if err != nil {
|
||||
h.sendACK(client, msg, -1, err.Error(), nil)
|
||||
return
|
||||
@@ -148,7 +157,7 @@ func (h *MeetingWSHandler) handleTransportConnect(client *ws.Client, msg *ws.Mes
|
||||
if !h.unmarshal(client, msg, &payload) {
|
||||
return
|
||||
}
|
||||
if err := h.signalSvc.OnTransportConnect(context.Background(), client.UserID, &payload); err != nil {
|
||||
if err := h.signalSvc.OnTransportConnect(h.newEventContext(), client.UserID, &payload); err != nil {
|
||||
h.sendACK(client, msg, -1, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
@@ -161,7 +170,7 @@ func (h *MeetingWSHandler) handleProduceStart(client *ws.Client, msg *ws.Message
|
||||
if !h.unmarshal(client, msg, &payload) {
|
||||
return
|
||||
}
|
||||
result, err := h.signalSvc.OnProduceStart(context.Background(), client.UserID, &payload)
|
||||
result, err := h.signalSvc.OnProduceStart(h.newEventContext(), client.UserID, &payload)
|
||||
if err != nil {
|
||||
h.sendACK(client, msg, -1, err.Error(), nil)
|
||||
return
|
||||
@@ -175,7 +184,7 @@ func (h *MeetingWSHandler) handleConsumeStart(client *ws.Client, msg *ws.Message
|
||||
if !h.unmarshal(client, msg, &payload) {
|
||||
return
|
||||
}
|
||||
info, err := h.signalSvc.OnConsumeStart(context.Background(), client.UserID, &payload)
|
||||
info, err := h.signalSvc.OnConsumeStart(h.newEventContext(), client.UserID, &payload)
|
||||
if err != nil {
|
||||
h.sendACK(client, msg, -1, err.Error(), nil)
|
||||
return
|
||||
@@ -189,7 +198,7 @@ func (h *MeetingWSHandler) handleConsumeResume(client *ws.Client, msg *ws.Messag
|
||||
if !h.unmarshal(client, msg, &payload) {
|
||||
return
|
||||
}
|
||||
if err := h.signalSvc.OnConsumeResume(context.Background(), client.UserID, &payload); err != nil {
|
||||
if err := h.signalSvc.OnConsumeResume(h.newEventContext(), client.UserID, &payload); err != nil {
|
||||
h.sendACK(client, msg, -1, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
@@ -202,7 +211,7 @@ func (h *MeetingWSHandler) handleProducerClose(client *ws.Client, msg *ws.Messag
|
||||
if !h.unmarshal(client, msg, &payload) {
|
||||
return
|
||||
}
|
||||
if err := h.signalSvc.OnProducerClose(context.Background(), client.UserID, &payload); err != nil {
|
||||
if err := h.signalSvc.OnProducerClose(h.newEventContext(), client.UserID, &payload); err != nil {
|
||||
h.sendACK(client, msg, -1, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user