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.
This commit is contained in:
@@ -291,7 +291,7 @@ func (c *Cache) StoreSource(
|
|||||||
// accounting insert is best-effort (the startup reconciliation pass
|
// accounting insert is best-effort (the startup reconciliation pass
|
||||||
// adopts any variant file that misses its accounting row).
|
// adopts any variant file that misses its accounting row).
|
||||||
func (c *Cache) StoreVariant(
|
func (c *Cache) StoreVariant(
|
||||||
cacheKey VariantKey, content io.Reader, contentType string,
|
ctx context.Context, cacheKey VariantKey, content io.Reader, contentType string,
|
||||||
) error {
|
) error {
|
||||||
if c.disabled {
|
if c.disabled {
|
||||||
return nil
|
return nil
|
||||||
@@ -302,7 +302,7 @@ func (c *Cache) StoreVariant(
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = c.db.Exec(`
|
_, err = c.db.ExecContext(ctx, `
|
||||||
INSERT INTO variant_content (cache_key, size_bytes, content_type)
|
INSERT INTO variant_content (cache_key, size_bytes, content_type)
|
||||||
VALUES (?, ?, ?)
|
VALUES (?, ?, ?)
|
||||||
ON CONFLICT(cache_key) DO UPDATE SET
|
ON CONFLICT(cache_key) DO UPDATE SET
|
||||||
|
|||||||
@@ -177,7 +177,8 @@ func TestCache_StoreAndLookup(t *testing.T) {
|
|||||||
cacheKey := CacheKey(req)
|
cacheKey := CacheKey(req)
|
||||||
outputContent := []byte("fake webp data")
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("StoreVariant() error = %v", err)
|
t.Fatalf("StoreVariant() error = %v", err)
|
||||||
}
|
}
|
||||||
@@ -295,7 +296,8 @@ func TestCache_VariantLookup(t *testing.T) {
|
|||||||
cacheKey := CacheKey(req)
|
cacheKey := CacheKey(req)
|
||||||
outputContent := []byte("output data")
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("StoreVariant() error = %v", err)
|
t.Fatalf("StoreVariant() error = %v", err)
|
||||||
}
|
}
|
||||||
@@ -344,7 +346,8 @@ func TestCache_GetVariant_ReturnsContentType(t *testing.T) {
|
|||||||
cacheKey := CacheKey(req)
|
cacheKey := CacheKey(req)
|
||||||
outputContent := []byte("output webp data")
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("StoreVariant() error = %v", err)
|
t.Fatalf("StoreVariant() error = %v", err)
|
||||||
}
|
}
|
||||||
@@ -395,7 +398,8 @@ func TestCache_GetVariant(t *testing.T) {
|
|||||||
cacheKey := CacheKey(req)
|
cacheKey := CacheKey(req)
|
||||||
outputContent := []byte("the actual output content")
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("StoreVariant() error = %v", err)
|
t.Fatalf("StoreVariant() error = %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ func storeEvictionTestVariant(
|
|||||||
) {
|
) {
|
||||||
t.Helper()
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("StoreVariant(%s) failed: %v", key, err)
|
t.Fatalf("StoreVariant(%s) failed: %v", key, err)
|
||||||
}
|
}
|
||||||
@@ -531,7 +531,7 @@ func assertDisabledCacheWritesAreNoOps(
|
|||||||
ctx := t.Context()
|
ctx := t.Context()
|
||||||
|
|
||||||
err := cache.StoreVariant(
|
err := cache.StoreVariant(
|
||||||
CacheKey(req), bytes.NewReader([]byte("data")), "image/webp",
|
ctx, CacheKey(req), bytes.NewReader([]byte("data")), "image/webp",
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("StoreVariant on disabled cache must be a no-op, got error: %v", err)
|
t.Fatalf("StoreVariant on disabled cache must be a no-op, got error: %v", err)
|
||||||
|
|||||||
@@ -425,7 +425,7 @@ func (s *Service) processAndStore(
|
|||||||
|
|
||||||
// Store variant to cache
|
// Store variant to cache
|
||||||
err = s.cache.StoreVariant(
|
err = s.cache.StoreVariant(
|
||||||
cacheKey, bytes.NewReader(processedData), processResult.ContentType,
|
ctx, cacheKey, bytes.NewReader(processedData), processResult.ContentType,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Warn("failed to store variant", "error", err)
|
s.log.Warn("failed to store variant", "error", err)
|
||||||
|
|||||||
Reference in New Issue
Block a user