Expire local static assets after 24 hours
This commit is contained in:
@@ -29,9 +29,35 @@ func (s *Server) startLocalTempAssetCleanup(ctx context.Context) {
|
||||
}
|
||||
|
||||
func (s *Server) cleanupExpiredLocalTempAssets(ctx context.Context, now time.Time) int {
|
||||
storageDir := strings.TrimSpace(s.cfg.LocalUploadedStorageDir)
|
||||
targets := []localTempAssetCleanupTarget{
|
||||
{
|
||||
StorageDir: s.cfg.LocalGeneratedStorageDir,
|
||||
FallbackDir: config.DefaultLocalGeneratedStorageDir,
|
||||
MarkRequestAsset: false,
|
||||
},
|
||||
{
|
||||
StorageDir: s.cfg.LocalUploadedStorageDir,
|
||||
FallbackDir: config.DefaultLocalUploadedStorageDir,
|
||||
MarkRequestAsset: true,
|
||||
},
|
||||
}
|
||||
deleted := 0
|
||||
for _, target := range targets {
|
||||
deleted += s.cleanupExpiredLocalTempAssetsInDir(ctx, now, target)
|
||||
}
|
||||
return deleted
|
||||
}
|
||||
|
||||
type localTempAssetCleanupTarget struct {
|
||||
StorageDir string
|
||||
FallbackDir string
|
||||
MarkRequestAsset bool
|
||||
}
|
||||
|
||||
func (s *Server) cleanupExpiredLocalTempAssetsInDir(ctx context.Context, now time.Time, target localTempAssetCleanupTarget) int {
|
||||
storageDir := strings.TrimSpace(target.StorageDir)
|
||||
if storageDir == "" {
|
||||
storageDir = config.DefaultLocalUploadedStorageDir
|
||||
storageDir = target.FallbackDir
|
||||
}
|
||||
entries, err := os.ReadDir(storageDir)
|
||||
if err != nil {
|
||||
@@ -44,7 +70,7 @@ func (s *Server) cleanupExpiredLocalTempAssets(ctx context.Context, now time.Tim
|
||||
expiredBefore := now.Add(-ttl)
|
||||
deleted := 0
|
||||
for _, entry := range entries {
|
||||
if entry.IsDir() || !strings.HasPrefix(entry.Name(), requestAssetFilePrefix) {
|
||||
if entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
info, err := entry.Info()
|
||||
@@ -60,7 +86,7 @@ func (s *Server) cleanupExpiredLocalTempAssets(ctx context.Context, now time.Tim
|
||||
continue
|
||||
}
|
||||
deleted++
|
||||
if s.store != nil {
|
||||
if target.MarkRequestAsset && strings.HasPrefix(entry.Name(), requestAssetFilePrefix) && s.store != nil {
|
||||
if err := s.store.MarkRequestAssetExpiredByLocalPath(ctx, localPath, now); err != nil && !store.IsUndefinedDatabaseObject(err) {
|
||||
s.logger.Warn("mark local temp asset expired failed", "path", localPath, "error", err)
|
||||
}
|
||||
|
||||
@@ -75,42 +75,51 @@ func TestCanonicalConversationMessageHashUsesTextAndAssetRefs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCleanupExpiredLocalTempAssetsOnlyDeletesExpiredPrefixedFiles(t *testing.T) {
|
||||
storageDir := t.TempDir()
|
||||
oldTemp := filepath.Join(storageDir, requestAssetFilePrefix+"old.png")
|
||||
freshTemp := filepath.Join(storageDir, requestAssetFilePrefix+"fresh.png")
|
||||
oldGenerated := filepath.Join(storageDir, "gateway-result-old.png")
|
||||
for _, path := range []string{oldTemp, freshTemp, oldGenerated} {
|
||||
func TestCleanupExpiredLocalTempAssetsDeletesExpiredStaticFiles(t *testing.T) {
|
||||
uploadedDir := t.TempDir()
|
||||
generatedDir := t.TempDir()
|
||||
oldUploaded := filepath.Join(uploadedDir, requestAssetFilePrefix+"old.png")
|
||||
freshUploaded := filepath.Join(uploadedDir, requestAssetFilePrefix+"fresh.png")
|
||||
oldGenerated := filepath.Join(generatedDir, "gateway-result-old.png")
|
||||
freshGenerated := filepath.Join(generatedDir, "gateway-result-fresh.png")
|
||||
for _, path := range []string{oldUploaded, freshUploaded, oldGenerated, freshGenerated} {
|
||||
if err := os.WriteFile(path, []byte("asset"), 0o644); err != nil {
|
||||
t.Fatalf("write fixture %s: %v", path, err)
|
||||
}
|
||||
}
|
||||
now := time.Now()
|
||||
if err := os.Chtimes(oldTemp, now.Add(-25*time.Hour), now.Add(-25*time.Hour)); err != nil {
|
||||
t.Fatalf("touch old temp: %v", err)
|
||||
for _, path := range []string{oldUploaded, oldGenerated} {
|
||||
if err := os.Chtimes(path, now.Add(-25*time.Hour), now.Add(-25*time.Hour)); err != nil {
|
||||
t.Fatalf("touch old static asset %s: %v", path, err)
|
||||
}
|
||||
}
|
||||
if err := os.Chtimes(freshTemp, now.Add(-23*time.Hour), now.Add(-23*time.Hour)); err != nil {
|
||||
t.Fatalf("touch fresh temp: %v", err)
|
||||
}
|
||||
if err := os.Chtimes(oldGenerated, now.Add(-25*time.Hour), now.Add(-25*time.Hour)); err != nil {
|
||||
t.Fatalf("touch old generated: %v", err)
|
||||
for _, path := range []string{freshUploaded, freshGenerated} {
|
||||
if err := os.Chtimes(path, now.Add(-23*time.Hour), now.Add(-23*time.Hour)); err != nil {
|
||||
t.Fatalf("touch fresh static asset %s: %v", path, err)
|
||||
}
|
||||
}
|
||||
server := &Server{
|
||||
cfg: config.Config{LocalUploadedStorageDir: storageDir, LocalTempAssetTTLHours: 24},
|
||||
cfg: config.Config{
|
||||
LocalGeneratedStorageDir: generatedDir,
|
||||
LocalUploadedStorageDir: uploadedDir,
|
||||
LocalTempAssetTTLHours: 24,
|
||||
},
|
||||
logger: slog.New(slog.NewTextHandler(io.Discard, nil)),
|
||||
}
|
||||
|
||||
deleted := server.cleanupExpiredLocalTempAssets(context.Background(), now)
|
||||
|
||||
if deleted != 1 {
|
||||
t.Fatalf("expected one expired temp asset delete, got %d", deleted)
|
||||
if deleted != 2 {
|
||||
t.Fatalf("expected two expired static asset deletes, got %d", deleted)
|
||||
}
|
||||
if _, err := os.Stat(oldTemp); !os.IsNotExist(err) {
|
||||
t.Fatalf("old prefixed temp asset should be deleted, stat err=%v", err)
|
||||
for _, path := range []string{oldUploaded, oldGenerated} {
|
||||
if _, err := os.Stat(path); !os.IsNotExist(err) {
|
||||
t.Fatalf("old static asset should be deleted %s, stat err=%v", path, err)
|
||||
}
|
||||
}
|
||||
for _, path := range []string{freshTemp, oldGenerated} {
|
||||
for _, path := range []string{freshUploaded, freshGenerated} {
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
t.Fatalf("non-expired or non-prefixed file should remain %s: %v", path, err)
|
||||
t.Fatalf("fresh static asset should remain %s: %v", path, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user