From 061a3545eb9550fc9b73f69366a8a69f955c4d3d Mon Sep 17 00:00:00 2001 From: sneak Date: Sun, 9 Aug 2026 13:37:12 +0000 Subject: [PATCH] refactor: propagate context into Cache.StoreVariant (noctx) The size-accounting INSERT in StoreVariant used db.Exec, and StoreVariant took no context at all, so the write was uncancellable and untraceable. Rather than paper over that with context.Background() at the call site, StoreVariant now takes a context.Context and uses ExecContext. The plumbing is small: the only production caller is Service.processAndStore, which already has the request context in scope, so the accounting insert now shares the lifetime of the request that produced the variant. Test callers pass t.Context(). The insert remains best-effort: a failure is logged and the startup and periodic reconciliation passes still adopt any variant file whose accounting row is missing. --- internal/imgcache/cache.go | 4 ++-- internal/imgcache/cache_internal_test.go | 12 ++++++++---- internal/imgcache/eviction_internal_test.go | 4 ++-- internal/imgcache/service.go | 2 +- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/internal/imgcache/cache.go b/internal/imgcache/cache.go index ffbd145..f31880b 100644 --- a/internal/imgcache/cache.go +++ b/internal/imgcache/cache.go @@ -291,7 +291,7 @@ func (c *Cache) StoreSource( // accounting insert is best-effort (the startup reconciliation pass // adopts any variant file that misses its accounting row). func (c *Cache) StoreVariant( - cacheKey VariantKey, content io.Reader, contentType string, + ctx context.Context, cacheKey VariantKey, content io.Reader, contentType string, ) error { if c.disabled { return nil @@ -302,7 +302,7 @@ func (c *Cache) StoreVariant( return err } - _, err = c.db.Exec(` + _, err = c.db.ExecContext(ctx, ` INSERT INTO variant_content (cache_key, size_bytes, content_type) VALUES (?, ?, ?) ON CONFLICT(cache_key) DO UPDATE SET diff --git a/internal/imgcache/cache_internal_test.go b/internal/imgcache/cache_internal_test.go index 3912bf8..b4026f5 100644 --- a/internal/imgcache/cache_internal_test.go +++ b/internal/imgcache/cache_internal_test.go @@ -177,7 +177,8 @@ func TestCache_StoreAndLookup(t *testing.T) { cacheKey := CacheKey(req) outputContent := []byte("fake webp data") - err = cache.StoreVariant(cacheKey, bytes.NewReader(outputContent), "image/webp") + err = cache.StoreVariant( + t.Context(), cacheKey, bytes.NewReader(outputContent), "image/webp") if err != nil { t.Fatalf("StoreVariant() error = %v", err) } @@ -295,7 +296,8 @@ func TestCache_VariantLookup(t *testing.T) { cacheKey := CacheKey(req) outputContent := []byte("output data") - err := cache.StoreVariant(cacheKey, bytes.NewReader(outputContent), "image/webp") + err := cache.StoreVariant( + t.Context(), cacheKey, bytes.NewReader(outputContent), "image/webp") if err != nil { t.Fatalf("StoreVariant() error = %v", err) } @@ -344,7 +346,8 @@ func TestCache_GetVariant_ReturnsContentType(t *testing.T) { cacheKey := CacheKey(req) outputContent := []byte("output webp data") - err := cache.StoreVariant(cacheKey, bytes.NewReader(outputContent), "image/webp") + err := cache.StoreVariant( + t.Context(), cacheKey, bytes.NewReader(outputContent), "image/webp") if err != nil { t.Fatalf("StoreVariant() error = %v", err) } @@ -395,7 +398,8 @@ func TestCache_GetVariant(t *testing.T) { cacheKey := CacheKey(req) outputContent := []byte("the actual output content") - err := cache.StoreVariant(cacheKey, bytes.NewReader(outputContent), "image/webp") + err := cache.StoreVariant( + t.Context(), cacheKey, bytes.NewReader(outputContent), "image/webp") if err != nil { t.Fatalf("StoreVariant() error = %v", err) } diff --git a/internal/imgcache/eviction_internal_test.go b/internal/imgcache/eviction_internal_test.go index 56434b3..0ff2ed8 100644 --- a/internal/imgcache/eviction_internal_test.go +++ b/internal/imgcache/eviction_internal_test.go @@ -114,7 +114,7 @@ func storeEvictionTestVariant( ) { t.Helper() - err := cache.StoreVariant(key, bytes.NewReader(content), "image/webp") + err := cache.StoreVariant(t.Context(), key, bytes.NewReader(content), "image/webp") if err != nil { t.Fatalf("StoreVariant(%s) failed: %v", key, err) } @@ -531,7 +531,7 @@ func assertDisabledCacheWritesAreNoOps( ctx := t.Context() err := cache.StoreVariant( - CacheKey(req), bytes.NewReader([]byte("data")), "image/webp", + ctx, CacheKey(req), bytes.NewReader([]byte("data")), "image/webp", ) if err != nil { t.Fatalf("StoreVariant on disabled cache must be a no-op, got error: %v", err) diff --git a/internal/imgcache/service.go b/internal/imgcache/service.go index bc0b68f..ecb745d 100644 --- a/internal/imgcache/service.go +++ b/internal/imgcache/service.go @@ -425,7 +425,7 @@ func (s *Service) processAndStore( // Store variant to cache err = s.cache.StoreVariant( - cacheKey, bytes.NewReader(processedData), processResult.ContentType, + ctx, cacheKey, bytes.NewReader(processedData), processResult.ContentType, ) if err != nil { s.log.Warn("failed to store variant", "error", err)