66 lines
2.6 KiB
Go
66 lines
2.6 KiB
Go
// Package roomtime runs room presence outbox consumers and exposes in-room duration compensation.
|
|
package roomtime
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"hyapp/pkg/xerr"
|
|
roomtimedomain "hyapp/services/user-service/internal/domain/roomtime"
|
|
)
|
|
|
|
// Repository applies room presence events and compensates abnormal open sessions.
|
|
type Repository interface {
|
|
ProcessRoomPresenceEvent(ctx context.Context, event roomtimedomain.RoomPresenceEvent) (roomtimedomain.ApplyResult, error)
|
|
CompensateOpenSessions(ctx context.Context, options roomtimedomain.CompensationOptions) (roomtimedomain.CompensationResult, error)
|
|
}
|
|
|
|
// Service owns the user in-room duration read model.
|
|
type Service struct {
|
|
repository Repository
|
|
}
|
|
|
|
// CompensationWorkerOptions controls abnormal open session closure.
|
|
type CompensationWorkerOptions struct {
|
|
WorkerID string
|
|
BatchSize int
|
|
OpenSessionMaxAge time.Duration
|
|
}
|
|
|
|
// New creates a room time service with the repository that owns idempotent application.
|
|
func New(repository Repository) *Service {
|
|
return &Service{repository: repository}
|
|
}
|
|
|
|
// ConsumeRoomPresenceEvent applies one MQ-delivered RoomUserJoined/RoomUserLeft/RoomUserKicked fact.
|
|
func (s *Service) ConsumeRoomPresenceEvent(ctx context.Context, event roomtimedomain.RoomPresenceEvent) (roomtimedomain.ApplyResult, error) {
|
|
if s == nil || s.repository == nil {
|
|
return roomtimedomain.ApplyResult{}, xerr.New(xerr.Unavailable, "room time repository is not configured")
|
|
}
|
|
switch event.EventType {
|
|
case roomtimedomain.RoomUserJoinedEventType, roomtimedomain.RoomUserLeftEventType, roomtimedomain.RoomUserKickedEventType:
|
|
default:
|
|
return roomtimedomain.ApplyResult{Skipped: true, Reason: "unsupported_event_type"}, nil
|
|
}
|
|
return s.repository.ProcessRoomPresenceEvent(ctx, event)
|
|
}
|
|
|
|
// ProcessOpenSessionCompensationBatch exposes one bounded compensation scan for cron-service.
|
|
func (s *Service) ProcessOpenSessionCompensationBatch(ctx context.Context, options CompensationWorkerOptions) (roomtimedomain.CompensationResult, error) {
|
|
if s == nil || s.repository == nil {
|
|
return roomtimedomain.CompensationResult{}, xerr.New(xerr.Unavailable, "room time repository is not configured")
|
|
}
|
|
if options.BatchSize <= 0 {
|
|
options.BatchSize = 200
|
|
}
|
|
if options.OpenSessionMaxAge <= 0 {
|
|
// stale worker 2 分钟内会把断线用户判离房;这里只兜 room-service 节点崩溃或 outbox 丢失的极端场景。
|
|
options.OpenSessionMaxAge = 24 * time.Hour
|
|
}
|
|
return s.repository.CompensateOpenSessions(ctx, roomtimedomain.CompensationOptions{
|
|
NowMs: time.Now().UnixMilli(),
|
|
BatchSize: options.BatchSize,
|
|
OpenSessionMaxAgeMs: options.OpenSessionMaxAge.Milliseconds(),
|
|
})
|
|
}
|