119 lines
3.2 KiB
Go
119 lines
3.2 KiB
Go
package service
|
||
|
||
import (
|
||
"context"
|
||
"log/slog"
|
||
"time"
|
||
|
||
"hyapp/pkg/appcode"
|
||
"hyapp/pkg/logx"
|
||
"hyapp/services/room-service/internal/room/outbox"
|
||
)
|
||
|
||
const roomDirectIMPublishTimeout = 2 * time.Second
|
||
|
||
func splitRoomDirectIMRecords(records []outbox.Record, suppressMirror map[string]bool) ([]outbox.Record, []outbox.Record) {
|
||
if len(records) == 0 {
|
||
return nil, nil
|
||
}
|
||
durable := make([]outbox.Record, 0, len(records))
|
||
directIM := make([]outbox.Record, 0)
|
||
for _, record := range records {
|
||
if roomDirectIMOnlyEventType(record.EventType) {
|
||
directIM = append(directIM, record)
|
||
continue
|
||
}
|
||
durable = append(durable, record)
|
||
if roomDirectIMMirrorEventType(record.EventType) && !suppressMirror[record.EventType] {
|
||
// 这类事件同时服务 UI 和业务事实消费:MySQL outbox 保证统计、任务、通知等可补偿,直接 IM 只给客户端低延迟展示。
|
||
directIM = append(directIM, record)
|
||
}
|
||
}
|
||
return durable, directIM
|
||
}
|
||
|
||
func roomDirectIMOnlyEventType(eventType string) bool {
|
||
switch eventType {
|
||
case "RoomHeatChanged",
|
||
"RoomRankChanged",
|
||
"RoomGiftBatchSent",
|
||
"RoomRocketFuelChanged",
|
||
"RoomRocketLaunched":
|
||
return true
|
||
default:
|
||
return false
|
||
}
|
||
}
|
||
|
||
func roomDirectIMMirrorEventType(eventType string) bool {
|
||
switch eventType {
|
||
case "RoomGiftSent",
|
||
"RoomUserJoined",
|
||
"RoomUserLeft",
|
||
"RoomMicChanged",
|
||
"RoomMicSeatLocked",
|
||
"RoomClosed",
|
||
"RoomUserKicked",
|
||
"RoomUserMuted",
|
||
"RoomUserUnbanned",
|
||
"RoomProfileUpdated",
|
||
"RoomBackgroundChanged",
|
||
"RoomChatEnabledChanged",
|
||
"RoomAdminChanged",
|
||
"RoomRocketIgnited":
|
||
return true
|
||
default:
|
||
return false
|
||
}
|
||
}
|
||
|
||
func (s *Service) publishDirectIMRecordsBestEffort(ctx context.Context, records []outbox.Record) {
|
||
if s == nil || len(records) == 0 {
|
||
return
|
||
}
|
||
if s.roomDisplayPublisher == nil {
|
||
logx.Warn(ctx, "room_direct_im_publish_skipped",
|
||
slog.String("node_id", s.nodeID),
|
||
slog.Int("record_count", len(records)),
|
||
slog.String("reason", "publisher_not_configured"),
|
||
)
|
||
return
|
||
}
|
||
scopedApp := appcode.FromContext(ctx)
|
||
copied := append([]outbox.Record(nil), records...)
|
||
for index := range copied {
|
||
copied[index].AppCode = appcode.Normalize(firstNonEmpty(copied[index].AppCode, scopedApp))
|
||
if copied[index].Envelope != nil {
|
||
copied[index].Envelope.AppCode = copied[index].AppCode
|
||
}
|
||
}
|
||
sortOutboxRecords(copied)
|
||
|
||
go func(records []outbox.Record) {
|
||
for _, record := range records {
|
||
if record.Envelope == nil {
|
||
logx.Warn(ctx, "room_direct_im_publish_skipped",
|
||
slog.String("node_id", s.nodeID),
|
||
slog.String("event_id", record.EventID),
|
||
slog.String("event_type", record.EventType),
|
||
slog.String("room_id", record.RoomID),
|
||
slog.String("reason", "nil_envelope"),
|
||
)
|
||
continue
|
||
}
|
||
publishCtx, cancel := context.WithTimeout(appcode.WithContext(context.Background(), record.AppCode), roomDirectIMPublishTimeout)
|
||
err := s.roomDisplayPublisher.PublishOutboxEvent(publishCtx, record.Envelope)
|
||
cancel()
|
||
if err != nil {
|
||
logx.Warn(ctx, "room_direct_im_publish_failed",
|
||
slog.String("node_id", s.nodeID),
|
||
slog.String("event_id", record.EventID),
|
||
slog.String("event_type", record.EventType),
|
||
slog.String("room_id", record.RoomID),
|
||
slog.String("error", trimOutboxError(err.Error())),
|
||
)
|
||
}
|
||
}
|
||
}(copied)
|
||
}
|