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

@@ -2,7 +2,6 @@ package service
import (
"context"
"log"
"time"
"with_you/internal/model"
@@ -179,7 +178,10 @@ func (s *userProfileAuditServiceImpl) GetPendingCounts(ctx context.Context) (int
func (s *userProfileAuditServiceImpl) reviewAvatarAsync(auditID, userID, avatarURL string) {
defer func() {
if r := recover(); r != nil {
log.Printf("[ERROR] Panic in avatar moderation async flow, audit=%s panic=%v", auditID, r)
zap.L().Error("Panic in avatar moderation async flow",
zap.String("audit_id", auditID),
zap.Any("panic", r),
)
}
}()
@@ -245,7 +247,10 @@ func (s *userProfileAuditServiceImpl) reviewAvatarAsync(auditID, userID, avatarU
func (s *userProfileAuditServiceImpl) reviewCoverAsync(auditID, userID, coverURL string) {
defer func() {
if r := recover(); r != nil {
log.Printf("[ERROR] Panic in cover moderation async flow, audit=%s panic=%v", auditID, r)
zap.L().Error("Panic in cover moderation async flow",
zap.String("audit_id", auditID),
zap.Any("panic", r),
)
}
}()
@@ -311,7 +316,10 @@ func (s *userProfileAuditServiceImpl) reviewCoverAsync(auditID, userID, coverURL
func (s *userProfileAuditServiceImpl) reviewBioAsync(auditID, userID, bio string) {
defer func() {
if r := recover(); r != nil {
log.Printf("[ERROR] Panic in bio moderation async flow, audit=%s panic=%v", auditID, r)
zap.L().Error("Panic in bio moderation async flow",
zap.String("audit_id", auditID),
zap.Any("panic", r),
)
}
}()