2026-06-16 17:00:06 +08:00

190 lines
7.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package grpc
import (
"context"
"time"
activityv1 "hyapp.local/api/proto/activity/v1"
"hyapp/pkg/appcode"
"hyapp/pkg/xerr"
achievementservice "hyapp/services/activity-service/internal/service/achievement"
agencyopeningservice "hyapp/services/activity-service/internal/service/agencyopening"
cpweeklyrankservice "hyapp/services/activity-service/internal/service/cpweeklyrank"
growthservice "hyapp/services/activity-service/internal/service/growth"
messageservice "hyapp/services/activity-service/internal/service/message"
roomturnoverrewardservice "hyapp/services/activity-service/internal/service/roomturnoverreward"
weeklystarservice "hyapp/services/activity-service/internal/service/weeklystar"
)
// CronServer exposes activity-service owned background batches to cron-service.
type CronServer struct {
activityv1.UnimplementedActivityCronServiceServer
message *messageservice.Service
growth *growthservice.Service
achievement *achievementservice.Service
weeklyStar *weeklystarservice.Service
roomReward *roomturnoverrewardservice.Service
agencyOpen *agencyopeningservice.Service
cpWeekly *cpweeklyrankservice.Service
}
// NewCronServer creates the internal cron adapter without exposing message storage.
func NewCronServer(messageSvc *messageservice.Service, growthSvc *growthservice.Service, achievementSvc *achievementservice.Service, weeklyStarSvc *weeklystarservice.Service, roomRewardSvc *roomturnoverrewardservice.Service, agencyOpeningSvc *agencyopeningservice.Service, cpWeeklyRankSvc *cpweeklyrankservice.Service) *CronServer {
server := &CronServer{message: messageSvc}
server.growth = growthSvc
server.achievement = achievementSvc
server.weeklyStar = weeklyStarSvc
server.roomReward = roomRewardSvc
server.agencyOpen = agencyOpeningSvc
server.cpWeekly = cpWeeklyRankSvc
return server
}
// ProcessMessageFanoutBatch claims and processes one message fanout page.
func (s *CronServer) ProcessMessageFanoutBatch(ctx context.Context, req *activityv1.CronBatchRequest) (*activityv1.CronBatchResponse, error) {
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
if s.message == nil {
return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "message service is not configured"))
}
processed, err := s.message.ProcessNextFanoutJob(ctx, messageservice.FanoutWorkerOptions{
WorkerID: req.GetWorkerId(),
BatchSize: int(req.GetBatchSize()),
LockTTL: durationFromMillis(req.GetLockTtlMs()),
})
if err != nil {
return nil, xerr.ToGRPCError(err)
}
if !processed {
return &activityv1.CronBatchResponse{}, nil
}
return &activityv1.CronBatchResponse{
ClaimedCount: 1,
ProcessedCount: 1,
SuccessCount: 1,
HasMore: true,
}, nil
}
// ProcessLevelRewardBatch claims and grants pending permanent level rewards.
func (s *CronServer) ProcessLevelRewardBatch(ctx context.Context, req *activityv1.CronBatchRequest) (*activityv1.CronBatchResponse, error) {
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
if s.growth == nil {
return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "growth service is not configured"))
}
claimed, processed, success, failure, hasMore, err := s.growth.ProcessLevelRewardBatch(ctx, req.GetRunId(), req.GetWorkerId(), int(req.GetBatchSize()), durationFromMillis(req.GetLockTtlMs()))
if err != nil {
return nil, xerr.ToGRPCError(err)
}
return &activityv1.CronBatchResponse{
ClaimedCount: claimed,
ProcessedCount: processed,
SuccessCount: success,
FailureCount: failure,
HasMore: hasMore,
}, nil
}
// ProcessAchievementRewardBatch claims and grants pending achievement badge/resource rewards.
func (s *CronServer) ProcessAchievementRewardBatch(ctx context.Context, req *activityv1.CronBatchRequest) (*activityv1.CronBatchResponse, error) {
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
if s.achievement == nil {
return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "achievement service is not configured"))
}
claimed, processed, success, failure, hasMore, err := s.achievement.ProcessAchievementRewardBatch(ctx, req.GetRunId(), req.GetWorkerId(), int(req.GetBatchSize()), durationFromMillis(req.GetLockTtlMs()))
if err != nil {
return nil, xerr.ToGRPCError(err)
}
return &activityv1.CronBatchResponse{
ClaimedCount: claimed,
ProcessedCount: processed,
SuccessCount: success,
FailureCount: failure,
HasMore: hasMore,
}, nil
}
// ProcessWeeklyStarSettlementBatch claims ended weekly-star cycles and grants Top rewards.
func (s *CronServer) ProcessWeeklyStarSettlementBatch(ctx context.Context, req *activityv1.CronBatchRequest) (*activityv1.CronBatchResponse, error) {
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
if s.weeklyStar == nil {
return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "weekly star service is not configured"))
}
claimed, processed, success, failure, hasMore, err := s.weeklyStar.ProcessSettlementBatch(ctx, req.GetRunId(), req.GetWorkerId(), req.GetBatchSize(), durationFromMillis(req.GetLockTtlMs()))
if err != nil {
return nil, xerr.ToGRPCError(err)
}
return &activityv1.CronBatchResponse{
ClaimedCount: claimed,
ProcessedCount: processed,
SuccessCount: success,
FailureCount: failure,
HasMore: hasMore,
}, nil
}
// ProcessCPWeeklyRankSettlementBatch closes the previous UTC CP week and grants configured Top rewards.
func (s *CronServer) ProcessCPWeeklyRankSettlementBatch(ctx context.Context, req *activityv1.CronBatchRequest) (*activityv1.CronBatchResponse, error) {
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
if s.cpWeekly == nil {
return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "cp weekly rank service is not configured"))
}
claimed, processed, success, failure, hasMore, err := s.cpWeekly.ProcessSettlementBatch(ctx, req.GetRunId(), req.GetWorkerId(), req.GetBatchSize())
if err != nil {
return nil, xerr.ToGRPCError(err)
}
return &activityv1.CronBatchResponse{
ClaimedCount: claimed,
ProcessedCount: processed,
SuccessCount: success,
FailureCount: failure,
HasMore: hasMore,
}, nil
}
// ProcessRoomTurnoverRewardSettlementBatch closes the previous UTC week and grants pending room rewards.
func (s *CronServer) ProcessRoomTurnoverRewardSettlementBatch(ctx context.Context, req *activityv1.CronBatchRequest) (*activityv1.CronBatchResponse, error) {
// cron-service 只负责调度activity-service 才拥有上一 UTC 周期认领 settlement 和发奖状态机。
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
if s.roomReward == nil {
return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "room turnover reward service is not configured"))
}
result, err := s.roomReward.ProcessSettlementBatch(ctx, int(req.GetBatchSize()))
if err != nil {
return nil, xerr.ToGRPCError(err)
}
return &activityv1.CronBatchResponse{
ClaimedCount: result.ClaimedCount,
ProcessedCount: result.ProcessedCount,
SuccessCount: result.SuccessCount,
FailureCount: result.FailureCount,
HasMore: result.HasMore,
}, nil
}
// ProcessAgencyOpeningSettlementBatch claims ended agency-opening cycles and grants leaderboard COIN rewards.
func (s *CronServer) ProcessAgencyOpeningSettlementBatch(ctx context.Context, req *activityv1.CronBatchRequest) (*activityv1.CronBatchResponse, error) {
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
if s.agencyOpen == nil {
return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "agency opening service is not configured"))
}
claimed, processed, success, failure, hasMore, err := s.agencyOpen.ProcessSettlementBatch(ctx, req.GetRunId(), req.GetWorkerId(), req.GetBatchSize(), durationFromMillis(req.GetLockTtlMs()))
if err != nil {
return nil, xerr.ToGRPCError(err)
}
return &activityv1.CronBatchResponse{
ClaimedCount: claimed,
ProcessedCount: processed,
SuccessCount: success,
FailureCount: failure,
HasMore: hasMore,
}, nil
}
func durationFromMillis(value int64) time.Duration {
if value <= 0 {
return 0
}
return time.Duration(value) * time.Millisecond
}