From 73165e4b79a68d24d61eced612adabccd4722e89 Mon Sep 17 00:00:00 2001 From: yancy Date: Tue, 13 Oct 2026 22:09:11 +0000 Subject: [PATCH] fix: prevent CleanOrphanUploadFiles from skipping records during offset pagination CleanOrphanUploadFiles queried file records with offset-based pagination (page=1,2,3,...) while simultaneously deleting orphan records that dropped out of the Status=Available filter. After a batch deletes N records, the remaining result set shrinks and records that were at positions page*pageSize and above slide into earlier slots. Advancing the page counter then skips past those shifted rows, leaving eligible orphans unprocessed for a later cleanup run. Track deletions in the current batch. When any deletions occur the result set has changed, so reset page to 1 and re-scan the front of the result. When no deletions occur the Available set is stable and incrementing the page counter is safe. Closes: #1631 Signed-off-by: yancy --- .../file_record/file_record_service.go | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/internal/service/file_record/file_record_service.go b/internal/service/file_record/file_record_service.go index aa526f014..532dc9b7d 100644 --- a/internal/service/file_record/file_record_service.go +++ b/internal/service/file_record/file_record_service.go @@ -105,6 +105,8 @@ func (fs *FileRecordService) CleanOrphanUploadFiles(ctx context.Context) { if len(fileRecordList) == 0 || total == 0 { break } + + deletedInBatch := 0 for _, fileRecord := range fileRecordList { // If this file record created in 48 hours, no need to check if fileRecord.CreatedAt.AddDate(0, 0, 2).After(time.Now()) { @@ -122,6 +124,8 @@ func (fs *FileRecordService) CleanOrphanUploadFiles(ctx context.Context) { } if err := fs.DeleteAndMoveFileRecord(ctx, fileRecord); err != nil { log.Error(err) + } else { + deletedInBatch++ } continue } @@ -152,9 +156,23 @@ func (fs *FileRecordService) CleanOrphanUploadFiles(ctx context.Context) { // Delete and move the file record if err := fs.DeleteAndMoveFileRecord(ctx, fileRecord); err != nil { log.Error(err) + } else { + deletedInBatch++ } } - page++ + + // When records are deleted, they no longer match the `Status = Available` + // filter. This shrinks the result set and shifts subsequent records to lower + // positions. Incrementing the page counter in that case would skip past the + // records that slid into the previous page window (see issue #1631). + // Reset to page 1 so the next query scans the current front of the result set. + // If no records were deleted in this batch the Available set is unchanged, so + // it is safe to move on to the next page normally. + if deletedInBatch > 0 { + page = 1 + } else { + page++ + } } }