feat(ws): implement WebSocket cluster mode with Redis Pub/Sub
All checks were successful
Build Backend / build (push) Successful in 2m0s
Build Backend / build-docker (push) Successful in 1m26s

Introduce a new WebSocket messaging architecture that supports both standalone and cluster modes. This allows for horizontal scaling of WebSocket servers by using Redis Pub/Sub to synchronize messages across multiple instances.

Key changes:
- Added `ws.MessagePublisher` interface to abstract message distribution.
- Implemented `ws.Bus` to handle cluster-mode messaging via Redis.
- Added `ws.OnlineTracker` to manage user online status across the cluster.
- Refactored multiple services (Chat, Group, Push, Call, etc.) to use the new `MessagePublisher` instead of a concrete `ws.Hub`.
- Added WebSocket configuration options (mode, instance ID, channel, TTL, heartbeat) to `config.yaml` and `config.go`.
- Updated dependency injection with Wire to support the new publisher and Redis client.
- Improved logging by replacing standard `log` with `zap` in several service components.
This commit is contained in:
2026-05-06 12:39:11 +08:00
parent d481742790
commit c630cbf4d0
22 changed files with 1082 additions and 120 deletions

View File

@@ -105,10 +105,10 @@ func ProvidePushService(
pushRepo repository.PushRecordRepository,
deviceTokenRepo repository.DeviceTokenRepository,
messageRepo repository.MessageRepository,
wsHub *ws.Hub,
publisher ws.MessagePublisher,
jpushClient *jpush.Client,
) service.PushService {
return service.NewPushService(pushRepo, deviceTokenRepo, messageRepo, wsHub, jpushClient)
return service.NewPushService(pushRepo, deviceTokenRepo, messageRepo, publisher, jpushClient)
}
// ProvideSystemMessageService 提供系统消息服务
@@ -205,12 +205,12 @@ func ProvideChannelService(channelRepo repository.ChannelRepository, cacheBacken
func ProvideChatService(
messageRepo repository.MessageRepository,
userRepo repository.UserRepository,
wsHub *ws.Hub,
publisher ws.MessagePublisher,
cacheBackend cache.Cache,
uploadService *service.UploadService,
pushService service.PushService,
) service.ChatService {
return service.NewChatService(messageRepo, userRepo, nil, wsHub, cacheBackend, uploadService, pushService)
return service.NewChatService(messageRepo, userRepo, nil, publisher, cacheBackend, uploadService, pushService)
}
// ProvideScheduleService 提供日程服务
@@ -236,10 +236,10 @@ func ProvideGroupService(
messageRepo repository.MessageRepository,
requestRepo repository.GroupJoinRequestRepository,
notifyRepo repository.SystemNotificationRepository,
wsHub *ws.Hub,
publisher ws.MessagePublisher,
cacheBackend cache.Cache,
) service.GroupService {
return service.NewGroupService(groupRepo, userRepo, messageRepo, requestRepo, notifyRepo, wsHub, cacheBackend)
return service.NewGroupService(groupRepo, userRepo, messageRepo, requestRepo, notifyRepo, publisher, cacheBackend)
}
// ProvideUploadService 提供上传服务
@@ -382,13 +382,13 @@ func ProvideHotRankWorker(cfg *config.Config, postRepo repository.PostRepository
func ProvideQRCodeLoginService(
redisClient *redis.Client,
wsHub *ws.Hub,
publisher ws.MessagePublisher,
jwtService *service.JWTService,
userService service.UserService,
activityService service.UserActivityService,
logService *service.LogService,
) *service.QRCodeLoginService {
return service.NewQRCodeLoginService(redisClient, wsHub, jwtService, userService, activityService, logService)
return service.NewQRCodeLoginService(redisClient, publisher, jwtService, userService, activityService, logService)
}
// ProvideMaterialService 提供学习资料服务
@@ -407,11 +407,12 @@ func parseDuration(s string) (time.Duration, error) {
// ProvideCallService 提供通话服务
func ProvideCallService(
callRepo repository.CallRepository,
wsHub *ws.Hub,
publisher ws.MessagePublisher,
cfg *config.Config,
db *gorm.DB,
redisClient *redis.Client,
) service.CallService {
return service.NewCallService(callRepo, wsHub, cfg, db)
return service.NewCallService(callRepo, publisher, cfg, db, redisClient)
}
// ProvideReportService 提供举报服务