46 lines
1.5 KiB
Go
46 lines
1.5 KiB
Go
package service
|
||
|
||
import (
|
||
"context"
|
||
"log"
|
||
|
||
"fashionapi/internal/pkg/storage"
|
||
"fashionapi/internal/repository"
|
||
)
|
||
|
||
// purgeOrphanImages 清理七牛/本地孤儿图片:仅当某 key 在所有图集/草稿表中
|
||
// 引用计数归零时才真正删除对象;否则保留(仍有其他图集在用,避免误删)。
|
||
//
|
||
// 设计要点(为何必须引用计数而非「删库即删七牛」):
|
||
// 七牛 key 为 sha1 内容寻址,同一张图跨图集共享同一 key。直接删会误伤其他图集。
|
||
// 另外,删除失败/计数失败一律「保守跳过」——宁可留文件,不冒误删被引用文件的风险。
|
||
//
|
||
// 参数 del 为 storage.Deleter(七牛或本地实现),由装配点按配置注入。
|
||
func purgeOrphanImages(ctx context.Context, media repository.MediaRepository, del storage.Deleter, keys []string) {
|
||
seen := make(map[string]struct{}, len(keys))
|
||
for _, k := range keys {
|
||
if k == "" {
|
||
continue
|
||
}
|
||
if _, ok := seen[k]; ok {
|
||
continue // 同一次批量去重,避免重复删
|
||
}
|
||
seen[k] = struct{}{}
|
||
|
||
n, err := media.CountImageKeyRefs(ctx, k)
|
||
if err != nil {
|
||
log.Printf("[purge] 引用计数失败,跳过 key=%s: %v", k, err)
|
||
continue
|
||
}
|
||
if n > 0 {
|
||
// 仍被引用(含其他图集/草稿),保留。
|
||
continue
|
||
}
|
||
if err := del.Delete(ctx, k); err != nil {
|
||
log.Printf("[purge] 七牛/本地删除失败,保留 key=%s: %v", k, err)
|
||
continue
|
||
}
|
||
log.Printf("[purge] 已清理孤儿图片 key=%s", k)
|
||
}
|
||
}
|