Skip to content

Commit 2d660fd

Browse files
authored
feat: batch tag cleanup deletions to avoid oversized lists (#103)
Process eligible tag IDs in fixed-size batches, removing history/relations/tags per batch and looping until no more tags remain while keeping the 500-view threshold intact Closes #100 ZerGo0 Bot Co-authored-by: ZerGo0 <ZerGo0@users.noreply.github.com>
1 parent ac5d586 commit 2d660fd

File tree

1 file changed

+54
-48
lines changed

1 file changed

+54
-48
lines changed

backend-go/workers/tag_cleanup.go

Lines changed: 54 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ import (
1313

1414
type TagCleanupWorker struct {
1515
BaseWorker
16-
db *gorm.DB
17-
minViews int64
16+
db *gorm.DB
17+
minViews int64
18+
batchSize int
1819
}
1920

2021
func NewTagCleanupWorker(db *gorm.DB, cfg *config.Config) *TagCleanupWorker {
@@ -24,6 +25,7 @@ func NewTagCleanupWorker(db *gorm.DB, cfg *config.Config) *TagCleanupWorker {
2425
BaseWorker: NewBaseWorker("tag-cleanup", interval),
2526
db: db,
2627
minViews: 500,
28+
batchSize: 500,
2729
}
2830
}
2931

@@ -36,51 +38,55 @@ func (w *TagCleanupWorker) Run(ctx context.Context) error {
3638

3739
zap.L().Info("Running tag cleanup", zap.Int64("minViews", w.minViews))
3840

39-
var tagCount int64
40-
if err := w.db.Model(&models.Tag{}).
41-
Where("view_count < ?", w.minViews).
42-
Count(&tagCount).Error; err != nil {
43-
return fmt.Errorf("failed to count tags for cleanup: %w", err)
41+
var totalDeleted int64
42+
43+
for {
44+
select {
45+
case <-ctx.Done():
46+
return ctx.Err()
47+
default:
48+
}
49+
50+
var tagIDs []string
51+
if err := w.db.Model(&models.Tag{}).
52+
Where("view_count < ?", w.minViews).
53+
Order("id").
54+
Limit(w.batchSize).
55+
Pluck("id", &tagIDs).Error; err != nil {
56+
return fmt.Errorf("failed to load tags for cleanup: %w", err)
57+
}
58+
59+
if len(tagIDs) == 0 {
60+
if totalDeleted == 0 {
61+
zap.L().Debug("No tags to cleanup")
62+
} else {
63+
zap.L().Info("Tag cleanup completed", zap.Int64("deleted", totalDeleted))
64+
}
65+
return nil
66+
}
67+
68+
tx := w.db.Begin()
69+
if err := tx.Where("tag_id IN (?)", tagIDs).Delete(&models.TagHistory{}).Error; err != nil {
70+
tx.Rollback()
71+
return fmt.Errorf("failed to delete tag history: %w", err)
72+
}
73+
74+
if err := tx.Where("tag_id IN (?) OR related_tag_id IN (?)", tagIDs, tagIDs).
75+
Delete(&models.TagRelationDaily{}).Error; err != nil {
76+
tx.Rollback()
77+
return fmt.Errorf("failed to delete tag relations: %w", err)
78+
}
79+
80+
result := tx.Where("id IN (?)", tagIDs).Delete(&models.Tag{})
81+
if result.Error != nil {
82+
tx.Rollback()
83+
return fmt.Errorf("failed to delete tags: %w", result.Error)
84+
}
85+
86+
if err := tx.Commit().Error; err != nil {
87+
return fmt.Errorf("failed to commit tag cleanup: %w", err)
88+
}
89+
90+
totalDeleted += result.RowsAffected
4491
}
45-
46-
if tagCount == 0 {
47-
zap.L().Debug("No tags to cleanup")
48-
return nil
49-
}
50-
51-
select {
52-
case <-ctx.Done():
53-
return ctx.Err()
54-
default:
55-
}
56-
57-
tx := w.db.Begin()
58-
tagSubquery := tx.Model(&models.Tag{}).
59-
Select("id").
60-
Where("view_count < ?", w.minViews)
61-
62-
if err := tx.Where("tag_id IN (?)", tagSubquery).Delete(&models.TagHistory{}).Error; err != nil {
63-
tx.Rollback()
64-
return fmt.Errorf("failed to delete tag history: %w", err)
65-
}
66-
67-
if err := tx.Where("tag_id IN (?) OR related_tag_id IN (?)", tagSubquery, tagSubquery).
68-
Delete(&models.TagRelationDaily{}).Error; err != nil {
69-
tx.Rollback()
70-
return fmt.Errorf("failed to delete tag relations: %w", err)
71-
}
72-
73-
result := tx.Where("view_count < ?", w.minViews).Delete(&models.Tag{})
74-
if result.Error != nil {
75-
tx.Rollback()
76-
return fmt.Errorf("failed to delete tags: %w", result.Error)
77-
}
78-
79-
if err := tx.Commit().Error; err != nil {
80-
return fmt.Errorf("failed to commit tag cleanup: %w", err)
81-
}
82-
83-
zap.L().Info("Tag cleanup completed", zap.Int64("deleted", result.RowsAffected))
84-
85-
return nil
8692
}

0 commit comments

Comments
 (0)