- StatisticInternalProvider: TrackEvent/BatchTrackEvent
- StatisticCombinedProvider: all 9 RPCs (7 dashboard + 2 event) on single service
- materializer: 4 MV REFRESH CONCURRENTLY + pg_try_advisory_lock + refresh_log
- dashboard_repo: 7 aggregation SQLs (week_rank / 7d curve / top5 / level dist / upgrade progress)
- dashboard_service: 7 RPCs with Redis 5min TTL + cache miss protection (1min empty)
- Cache wrapper: JSON serialize + format dash:{rpc}:{starID}:{userID}
- main.go: integrated workers + Dubbo triple server :20009
- cross-service userService.GetFanProfile (for crystal_balance)
- client/user_rpc_client.go
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
66 lines
1.9 KiB
Go
66 lines
1.9 KiB
Go
package provider
|
||
|
||
import (
|
||
"context"
|
||
"time"
|
||
|
||
"go.uber.org/zap"
|
||
|
||
"github.com/topfans/backend/pkg/logger"
|
||
pb "github.com/topfans/backend/pkg/proto/statistic"
|
||
eventPb "github.com/topfans/backend/pkg/proto/event"
|
||
"github.com/topfans/backend/services/statisticService/model"
|
||
"github.com/topfans/backend/services/statisticService/service"
|
||
)
|
||
|
||
// StatisticInternalProvider 实现 Dubbo StatisticService 中的事件相关 RPC
|
||
// (TrackEvent / BatchTrackEvent)
|
||
// 业务侧通过 gRPC 调用此处
|
||
type StatisticInternalProvider struct {
|
||
eventSvc *service.EventService
|
||
}
|
||
|
||
// NewStatisticInternalProvider 构造
|
||
func NewStatisticInternalProvider(eventSvc *service.EventService) *StatisticInternalProvider {
|
||
return &StatisticInternalProvider{eventSvc: eventSvc}
|
||
}
|
||
|
||
// TrackEvent 接收单个事件
|
||
func (p *StatisticInternalProvider) TrackEvent(ctx context.Context, e *eventPb.Event) (*pb.TrackEventResponse, error) {
|
||
logger.Logger.Debug("StatisticInternalProvider.TrackEvent",
|
||
zap.String("event_id", e.EventId),
|
||
zap.String("event_type", e.EventType))
|
||
return p.eventSvc.TrackEvent(ctx, toModel(e))
|
||
}
|
||
|
||
// BatchTrackEvent 批量接收事件
|
||
func (p *StatisticInternalProvider) BatchTrackEvent(ctx context.Context, req *eventPb.BatchEventRequest) (*pb.TrackEventResponse, error) {
|
||
events := make([]*model.Event, 0, len(req.Events))
|
||
for _, e := range req.Events {
|
||
events = append(events, toModel(e))
|
||
}
|
||
return p.eventSvc.BatchTrackEvent(ctx, events)
|
||
}
|
||
|
||
// toModel protobuf -> domain model
|
||
func toModel(e *eventPb.Event) *model.Event {
|
||
occurredAt := time.UnixMilli(e.OccurredAt)
|
||
receivedAt := time.UnixMilli(e.ReceivedAt)
|
||
if receivedAt.IsZero() {
|
||
receivedAt = time.Now()
|
||
}
|
||
props := e.Properties
|
||
if props == nil {
|
||
props = map[string]string{}
|
||
}
|
||
return &model.Event{
|
||
EventID: e.EventId,
|
||
UserID: e.UserId,
|
||
StarID: e.StarId,
|
||
EventType: e.EventType,
|
||
OccurredAt: occurredAt,
|
||
ReceivedAt: receivedAt,
|
||
Properties: props,
|
||
}
|
||
}
|