monorepo/cloud/maplepress-backend/internal/usecase/site/reset_usage.go

127 lines
3.4 KiB
Go

package site
import (
"context"
"fmt"
"time"
"go.uber.org/zap"
domainsite "codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/domain/site"
)
// ResetMonthlyUsageUseCase handles resetting monthly usage counters for all sites (for billing cycles)
type ResetMonthlyUsageUseCase struct {
siteRepo domainsite.Repository
logger *zap.Logger
}
// ProvideResetMonthlyUsageUseCase creates a new ResetMonthlyUsageUseCase
func ProvideResetMonthlyUsageUseCase(
siteRepo domainsite.Repository,
logger *zap.Logger,
) *ResetMonthlyUsageUseCase {
return &ResetMonthlyUsageUseCase{
siteRepo: siteRepo,
logger: logger.Named("reset-monthly-usage-usecase"),
}
}
// ResetUsageOutput is the output after resetting usage counters
type ResetUsageOutput struct {
ProcessedSites int `json:"processed_sites"`
ResetCount int `json:"reset_count"`
FailedCount int `json:"failed_count"`
ProcessedAt time.Time `json:"processed_at"`
}
// Execute resets monthly usage counters for all sites (for billing cycles)
func (uc *ResetMonthlyUsageUseCase) Execute(ctx context.Context) (*ResetUsageOutput, error) {
uc.logger.Info("starting monthly usage counter reset for all sites")
startTime := time.Now()
processedSites := 0
resetCount := 0
failedCount := 0
// Pagination settings
const pageSize = 100
var pageState []byte
// Iterate through all sites using pagination
for {
// Get a batch of sites
sites, nextPageState, err := uc.siteRepo.GetAllSitesForUsageReset(ctx, pageSize, pageState)
if err != nil {
uc.logger.Error("failed to get sites for usage reset", zap.Error(err))
return nil, fmt.Errorf("failed to get sites: %w", err)
}
// Process each site in the batch
for _, site := range sites {
processedSites++
// Check if usage needs to be reset (monthly billing cycle)
now := time.Now()
needsReset := false
// Check if it's been a month since last reset
if site.LastResetAt.AddDate(0, 1, 0).Before(now) {
needsReset = true
}
if !needsReset {
uc.logger.Debug("site usage not due for reset",
zap.String("site_id", site.ID.String()),
zap.String("domain", site.Domain),
zap.Time("last_reset_at", site.LastResetAt))
continue
}
// Reset the usage counters
site.ResetMonthlyUsage()
// Update the site in database
if err := uc.siteRepo.UpdateUsage(ctx, site); err != nil {
uc.logger.Error("failed to reset usage for site",
zap.String("site_id", site.ID.String()),
zap.String("domain", site.Domain),
zap.Error(err))
failedCount++
continue
}
resetCount++
uc.logger.Debug("reset usage for site",
zap.String("site_id", site.ID.String()),
zap.String("domain", site.Domain),
zap.Time("last_reset_at", site.LastResetAt))
}
// Check if there are more pages
if len(nextPageState) == 0 {
break
}
pageState = nextPageState
uc.logger.Info("processed batch of sites",
zap.Int("batch_size", len(sites)),
zap.Int("total_processed", processedSites),
zap.Int("reset_count", resetCount),
zap.Int("failed_count", failedCount))
}
uc.logger.Info("monthly usage counter reset completed",
zap.Int("processed_sites", processedSites),
zap.Int("reset_count", resetCount),
zap.Int("failed_count", failedCount),
zap.Duration("duration", time.Since(startTime)))
return &ResetUsageOutput{
ProcessedSites: processedSites,
ResetCount: resetCount,
FailedCount: failedCount,
ProcessedAt: time.Now(),
}, nil
}