Commit 0d06714a92

0d06714a922332eca48f3ca81fe3c721af687115

parent: 8375b863f5

Verified · cmc

cmc <hello@cleberg.net> · 2026-09-26 18:48 UTC

Keep recently modified stale derivative dirs during prune

A request holding an older library snapshot may still be writing into a
stale version directory. Skip directories modified within the last five
minutes; a later prune removes them.

Closes #1

Layout: unified · split

internal/render/render.go +8
@@ -8,6 +8,7 @@ import (
88 "path/filepath"
99 "slices"
1010 "strconv"
11 "time"
1112
1213 "golang.org/x/sync/singleflight"
1314
@@ -84,6 +85,10 @@ func (r *Renderer) generate(it *library.Item, w int, dst string) error {
8485 return os.Rename(tmp.Name(), dst)
8586}
8687
88// pruneGrace keeps stale directories modified this recently, since a request
89// holding an older library snapshot may still be writing into them.
90const pruneGrace = 5 * time.Minute
91
8792// Prune removes derivative directories for items no longer in lib or whose source changed.
8893func (r *Renderer) Prune(lib *library.Library) error {
8994 keep := map[string]bool{}
@@ -99,6 +104,9 @@ func (r *Renderer) Prune(lib *library.Library) error {
99104 var firstErr error
100105 for _, v := range versions {
101106 if !keep[v] {
107 if fi, err := os.Stat(v); err == nil && time.Since(fi.ModTime()) < pruneGrace {
108 continue
109 }
102110 if err := os.RemoveAll(v); err != nil {
103111 log.Printf("prune %s: %v", v, err)
104112 if firstErr == nil {
internal/render/render_test.go +19
@@ -151,6 +151,10 @@ func TestPrune(t *testing.T) {
151151 t.Fatal(err)
152152 }
153153 }
154 past := time.Now().Add(-2 * pruneGrace)
155 for _, it := range []*library.Item{cur, old, gone} {
156 os.Chtimes(filepath.Dir(r.Path(it, 480)), past, past)
157 }
154158 lib := &library.Library{Albums: []*library.Album{{Slug: "tokyo", Items: []*library.Item{cur}}}}
155159 if err := r.Prune(lib); err != nil {
156160 t.Fatal(err)
@@ -164,3 +168,18 @@ func TestPrune(t *testing.T) {
164168 }
165169 }
166170}
171
172func TestPruneKeepsRecentlyModifiedStaleDir(t *testing.T) {
173 f := &fakeFormat{}
174 r := New(t.TempDir(), 1)
175 old := item(f)
176 if _, err := r.Get(old, 480); err != nil {
177 t.Fatal(err)
178 }
179 if err := r.Prune(&library.Library{}); err != nil {
180 t.Fatal(err)
181 }
182 if _, err := os.Stat(r.Path(old, 480)); err != nil {
183 t.Fatalf("recently written stale dir removed: %v", err)
184 }
185}