gpt
This commit is contained in:
+29
-43
@@ -82,37 +82,9 @@ func genUUID() string {
|
||||
|
||||
// recordDailyUsage 记录用户当日使用计数(best-effort,用于统计,不作为硬限制;失败仅告警)。
|
||||
// kind 复用 QuotaType 语义:QuotaTypeAI / QuotaTypeOutfitShare / QuotaTypeClosetShare。
|
||||
func recordDailyUsage(ctx context.Context, userID int64, kind int8) {
|
||||
usageDao := mysqldao.NewUserDailyUsageDao()
|
||||
statDate := todayStatDate()
|
||||
|
||||
// 确保当日计数行存在。
|
||||
if _, err := usageDao.UserDailyUsageGetByUserIDAndDate(ctx, userID, statDate); err != nil {
|
||||
if isNotFound(err) {
|
||||
if cerr := usageDao.UserDailyUsageCreate(ctx, &mysqlmodel.UserDailyUsage{
|
||||
UserID: userID,
|
||||
StatDate: statDate,
|
||||
}); cerr != nil {
|
||||
slog.WarnContext(ctx, "create daily usage failed", "user_id", userID, "error", cerr)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
slog.WarnContext(ctx, "get daily usage failed", "user_id", userID, "error", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
switch kind {
|
||||
case QuotaTypeAI:
|
||||
err = usageDao.UserDailyUsageIncrementAI(ctx, userID, statDate)
|
||||
case QuotaTypeOutfitShare:
|
||||
err = usageDao.UserDailyUsageIncrementOutfitShare(ctx, userID, statDate)
|
||||
case QuotaTypeClosetShare:
|
||||
err = usageDao.UserDailyUsageIncrementClosetShare(ctx, userID, statDate)
|
||||
}
|
||||
if err != nil {
|
||||
slog.WarnContext(ctx, "increment daily usage failed", "user_id", userID, "kind", kind, "error", err)
|
||||
func recordDailyUsage(ctx context.Context, userID int64, kind int8, delta int64) {
|
||||
if err := mysqldao.NewUserDailyUsageDao().UserDailyUsageAdjust(ctx, userID, todayStatDate(), kind, delta); err != nil {
|
||||
slog.WarnContext(ctx, "adjust daily usage failed", "user_id", userID, "kind", kind, "delta", delta, "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,16 +188,24 @@ func dailyQuotaKey(quotaType int8, userID int64, date int64) string {
|
||||
}
|
||||
}
|
||||
|
||||
// getDailyUsed 读取当日已用计数(Redis 优先,异常回落 MySQL 统计)。
|
||||
// getDailyUsed 读取 MySQL 权威当日计数;数据库异常时只把 Redis 作为展示兜底。
|
||||
func getDailyUsed(ctx context.Context, userID int64, quotaType int8) int64 {
|
||||
key := dailyQuotaKey(quotaType, userID, todayStatDate())
|
||||
if key == "" {
|
||||
return 0
|
||||
usage, err := mysqldao.NewUserDailyUsageDao().UserDailyUsageGetByUserIDAndDate(ctx, userID, todayStatDate())
|
||||
if err == nil {
|
||||
switch quotaType {
|
||||
case QuotaTypeAI:
|
||||
return usage.AIRecommendCount
|
||||
case QuotaTypeOutfitShare:
|
||||
return usage.OutfitShareCount
|
||||
case QuotaTypeClosetShare:
|
||||
return usage.ClosetShareCount
|
||||
}
|
||||
}
|
||||
if val, err := redisdao.DailyQuotaValue(ctx, key); err == nil {
|
||||
key := dailyQuotaKey(quotaType, userID, todayStatDate())
|
||||
if val, rerr := redisdao.DailyQuotaValue(ctx, key); rerr == nil {
|
||||
return val
|
||||
}
|
||||
return getDailyUsedFromMySQL(ctx, userID, quotaType)
|
||||
return 0
|
||||
}
|
||||
|
||||
// getDailyUsedFromMySQL 从 user_daily_usages 读取当日计数(Redis 故障兜底)。
|
||||
@@ -257,15 +237,17 @@ func consumeDailyQuota(ctx context.Context, userID int64, quotaType int8, n int6
|
||||
if key == "" {
|
||||
return errcode.QuotaInsufficient
|
||||
}
|
||||
val, err := redisdao.DailyQuotaConsume(ctx, key, quota.Total, n)
|
||||
consumed, err := mysqldao.NewUserDailyUsageDao().UserDailyUsageConsume(ctx, userID, todayStatDate(), quotaType, n, quota.Total)
|
||||
if err != nil {
|
||||
return errcode.CacheError
|
||||
return errcode.DatabaseError
|
||||
}
|
||||
if val < 0 {
|
||||
if !consumed {
|
||||
return errcode.QuotaInsufficient
|
||||
}
|
||||
// 同步 MySQL 当日计数(统计/兜底)。
|
||||
recordDailyUsage(ctx, userID, quotaType)
|
||||
// Redis 只作缓存;删除后下次从 MySQL 权威计数恢复,不受丢键影响。
|
||||
if err := redisdao.DailyQuotaDelete(ctx, key); err != nil {
|
||||
slog.WarnContext(ctx, "delete daily quota cache failed", "user_id", userID, "quota_type", quotaType, "error", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -275,8 +257,12 @@ func refundDailyQuota(ctx context.Context, userID int64, quotaType int8, n int64
|
||||
if key == "" {
|
||||
return
|
||||
}
|
||||
if err := redisdao.DailyQuotaRefund(ctx, key, n); err != nil {
|
||||
if err := mysqldao.NewUserDailyUsageDao().UserDailyUsageAdjust(ctx, userID, todayStatDate(), quotaType, -n); err != nil {
|
||||
slog.WarnContext(ctx, "refund daily quota failed", "user_id", userID, "quota_type", quotaType, "error", err)
|
||||
return
|
||||
}
|
||||
if err := redisdao.DailyQuotaDelete(ctx, key); err != nil {
|
||||
slog.WarnContext(ctx, "delete daily quota cache after refund failed", "user_id", userID, "quota_type", quotaType, "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user