package service import ( "context" "log" "fashionapi/internal/pkg/storage" "fashionapi/internal/repository" ) // purgeOrphanImages 清理S4/本地孤儿图片:仅当某 key 在所有图集/草稿表中 // 引用计数归零时才真正删除对象;否则保留(仍有其他图集在用,避免误删)。 // // 设计要点(为何必须引用计数而非「删库即删S4」): // S4 key 为 sha1 内容寻址,同一张图跨图集共享同一 key。直接删会误伤其他图集。 // 另外,删除失败/计数失败一律「保守跳过」——宁可留文件,不冒误删被引用文件的风险。 // // 参数 del 为 storage.Deleter(S4或本地实现),由装配点按配置注入。 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] S4/本地删除失败,保留 key=%s: %v", k, err) continue } log.Printf("[purge] 已清理孤儿图片 key=%s", k) } }