Files
silo-server/internal/adminjob/image_cache_cleanup.go
T

97 lines
2.5 KiB
Go

package adminjob
import (
"context"
"encoding/json"
"fmt"
"log/slog"
)
const JobTypeImageCacheCleanup = "image_cache_cleanup"
type ImageCacheCleanupRequest struct {
LibraryID int `json:"library_id"`
LibraryName string `json:"library_name"`
Prefixes []string `json:"prefixes"`
}
type ImageCacheCleanupResult struct {
LibraryID int `json:"library_id"`
LibraryName string `json:"library_name"`
DeletedPrefixes int `json:"deleted_prefixes"`
DeletedS3Objects int `json:"deleted_s3_objects"`
}
type imageCacheCleanupExecutor interface {
Execute(ctx context.Context, req ImageCacheCleanupRequest, progress func(current, total int, message string)) (*ImageCacheCleanupResult, error)
}
type ImageCacheCleanupExecutor struct {
s3 S3PrefixDeleter
}
func NewImageCacheCleanupExecutor(s3 S3PrefixDeleter) *ImageCacheCleanupExecutor {
if s3 == nil {
return nil
}
return &ImageCacheCleanupExecutor{s3: s3}
}
func (e *ImageCacheCleanupExecutor) Execute(
ctx context.Context,
req ImageCacheCleanupRequest,
progress func(current, total int, message string),
) (*ImageCacheCleanupResult, error) {
if e == nil || e.s3 == nil {
return nil, fmt.Errorf("image cache cleanup executor is not configured")
}
if len(req.Prefixes) == 0 {
return &ImageCacheCleanupResult{
LibraryID: req.LibraryID,
LibraryName: req.LibraryName,
DeletedPrefixes: 0,
DeletedS3Objects: 0,
}, nil
}
total := len(req.Prefixes)
deletedPrefixes := 0
deletedObjects := 0
bucket := e.s3.Bucket()
for index, prefix := range req.Prefixes {
if progress != nil {
progress(index, total, fmt.Sprintf("Cleaning cached images %d/%d", index+1, total))
}
n, err := e.s3.DeletePrefix(ctx, bucket, prefix)
if err != nil {
slog.Warn("image cache cleanup: s3 delete failed", "prefix", prefix, "error", err)
continue
}
deletedPrefixes++
deletedObjects += n
}
if progress != nil {
progress(total, total, "Cached image cleanup completed")
}
return &ImageCacheCleanupResult{
LibraryID: req.LibraryID,
LibraryName: req.LibraryName,
DeletedPrefixes: deletedPrefixes,
DeletedS3Objects: deletedObjects,
}, nil
}
func decodeImageCacheCleanupRequest(data json.RawMessage) (ImageCacheCleanupRequest, error) {
var req ImageCacheCleanupRequest
if len(data) == 0 {
return req, fmt.Errorf("missing image cache cleanup payload")
}
if err := json.Unmarshal(data, &req); err != nil {
return req, fmt.Errorf("invalid image cache cleanup request payload: %w", err)
}
return req, nil
}