Version: 0.3.0.dev.260212

refactor: ♻️ 基于 gorm 钩子实现自动缓存失效机制,再也不用牵一发而动全身写删缓存逻辑了~

- 通过 gorm hook 监听 MySQL 数据变更 🧩
- 自动删除对应表相关缓存,实现缓存失效自动化 🔄
- 移除原本写在 sv 层的手动删缓存逻辑 🧹
- 解耦业务逻辑与缓存控制,结构更加清晰 

fix: 🐛 修复将任务类加入日程接口的时间字段遗漏问题

- 由于前版本 MySQL 表结构更新
- 漏写插入起始时间字段逻辑,导致500报错,现已补充 ⏱️

fix: 🐛 修复获取最近已完成任务列表接口的多个问题

- 移除不应存在的幂等键 🔁
- 修复“一个event输出多次”的问题(原因出自 dto 转换函数) 🔧

undo: ⚠️ 删除任务类接口未处理已安排任务块的解除逻辑

- 当前删除任务类时,未解除已被安排的任务块
- 该逻辑存在缺陷,计划在后续版本内修复 🛠️
This commit is contained in:
LoveLosita
2026-02-12 21:34:01 +08:00
parent 6dd1f656dc
commit 63500b3b2a
11 changed files with 451 additions and 175 deletions

View File

@@ -47,18 +47,18 @@ func (d *CacheDAO) AddTaskClassList(ctx context.Context, userID int, list *model
return d.client.Set(ctx, key, data, 30*time.Minute).Err()
}
func (d *CacheDAO) GetTaskClassList(ctx context.Context, userID int) (model.UserGetTaskClassesResponse, error) {
func (d *CacheDAO) GetTaskClassList(ctx context.Context, userID int) (*model.UserGetTaskClassesResponse, error) {
key := fmt.Sprintf("smartflow:task_classes:%d", userID)
var resp model.UserGetTaskClassesResponse
// 1. 从 Redis 获取字符串
val, err := d.client.Get(ctx, key).Result()
if err != nil {
// 注意:如果是 redis.Nil交给 Service 层处理查库逻辑
return resp, err
return &resp, err
}
// 2. 反序列化:将 JSON 还原回结构体
err = json.Unmarshal([]byte(val), &resp)
return resp, err
return &resp, err
}
func (d *CacheDAO) DeleteTaskClassList(ctx context.Context, userID int) error {
@@ -136,3 +136,73 @@ func (d *CacheDAO) DeleteUserTodayScheduleFromCache(ctx context.Context, userID
key := fmt.Sprintf("smartflow:today_schedule:%d", userID)
return d.client.Del(ctx, key).Err()
}
func (d *CacheDAO) GetUserWeeklyScheduleFromCache(ctx context.Context, userID int, week int) (*model.UserWeekSchedule, error) {
key := fmt.Sprintf("smartflow:weekly_schedule:%d:%d", userID, week)
var schedules model.UserWeekSchedule
val, err := d.client.Get(ctx, key).Result()
if err != nil {
return nil, err // 注意:如果是 redis.Nil交给 Service 层处理查库逻辑
}
err = json.Unmarshal([]byte(val), &schedules)
return &schedules, err
}
func (d *CacheDAO) SetUserWeeklyScheduleToCache(ctx context.Context, userID int, schedules *model.UserWeekSchedule) error {
key := fmt.Sprintf("smartflow:weekly_schedule:%d:%d", userID, schedules.Week)
data, err := json.Marshal(schedules)
if err != nil {
return err
}
// 设置过期时间为一天
return d.client.Set(ctx, key, data, 24*time.Hour).Err()
}
func (d *CacheDAO) DeleteUserWeeklyScheduleFromCache(ctx context.Context, userID int, week int) error {
key := fmt.Sprintf("smartflow:weekly_schedule:%d:%d", userID, week)
return d.client.Del(ctx, key).Err()
}
func (d *CacheDAO) GetUserRecentCompletedSchedulesFromCache(ctx context.Context, userID, index, limit int) (model.UserRecentCompletedScheduleResponse, error) {
key := fmt.Sprintf("smartflow:recent_completed_schedules:%d:%d:%d", userID, index, limit)
var resp model.UserRecentCompletedScheduleResponse
val, err := d.client.Get(ctx, key).Result()
if err != nil {
return resp, err // 注意:如果是 redis.Nil交给 Service 层处理查库逻辑
}
err = json.Unmarshal([]byte(val), &resp)
return resp, err
}
func (d *CacheDAO) SetUserRecentCompletedSchedulesToCache(ctx context.Context, userID, index, limit int, resp model.UserRecentCompletedScheduleResponse) error {
key := fmt.Sprintf("smartflow:recent_completed_schedules:%d:%d:%d", userID, index, limit)
data, err := json.Marshal(resp)
if err != nil {
return err
}
// 设置过期时间为30分钟
return d.client.Set(ctx, key, data, 30*time.Minute).Err()
}
func (d *CacheDAO) DeleteUserRecentCompletedSchedulesFromCache(ctx context.Context, userID int) error {
pattern := fmt.Sprintf("smartflow:recent_completed_schedules:%d:*", userID)
var cursor uint64
for {
keys, next, err := d.client.Scan(ctx, cursor, pattern, 500).Result()
if err != nil {
return err
}
if len(keys) > 0 {
// 用 UNLINK\(\) 异步删除,降低阻塞风险;如需强一致删除可改用 Del\(\)
if err := d.client.Unlink(ctx, keys...).Err(); err != nil {
return err
}
}
cursor = next
if cursor == 0 {
break
}
}
return nil
}