Count a late hit, and report no totals on a disabled cache (closes #56)
check / check (push) Successful in 3m12s

A hit is now counted with the request context detached from its
cancellation, as the miss already is, so a hit served after the client
left or the request timed out still moves the hit count. On a disabled
disk cache, Stats reports no items and no size, whatever rows an earlier
run left in the database; the size already followed that rule.

Model: opus-5-5
This commit is contained in:
2026-09-29 02:46:31 +00:00
parent 3daa416f4b
commit 31ed20ec9e
3 changed files with 24 additions and 18 deletions
+8 -6
View File
@@ -46,12 +46,14 @@ exhaustion
counts the cached source images and processed variants (`source_content` counts the cached source images and processed variants (`source_content`
plus `variant_content`) and takes their size from `Cache.UsageBytes`, plus `variant_content`) and takes their size from `Cache.UsageBytes`,
instead of reading `request_cache` and `output_content`, which nothing instead of reading `request_cache` and `output_content`, which nothing
writes; those two tables are left in the schema. A miss is counted after writes; those two tables are left in the schema; a disabled disk cache
it is served or fails, even when the request context has ended by then, reports no items and no size. A hit is counted even when the request
with the bytes it read from upstream, so `upstream_fetch_count` and context has ended. A miss is counted after it is served or fails, also
`upstream_fetch_bytes` move, including for an upstream body that fails when the request context has ended by then, with the bytes it read from
partway or a fetched source that then fails the magic byte check; upstream, so `upstream_fetch_count` and `upstream_fetch_bytes` move,
`transform_count` counts each image the image processor transcodes. including for an upstream body that fails partway or a fetched source
that then fails the magic byte check; `transform_count` counts each image
the image processor transcodes.
- 2026-09-28 strip metadata from processed images (closes #82): every output is - 2026-09-28 strip metadata from processed images (closes #82): every output is
exported with govips' `StripMetadata`, so it carries no EXIF, XMP, IPTC or ICC exported with govips' `StripMetadata`, so it carries no EXIF, XMP, IPTC or ICC
profile; the image is first turned upright with `AutoRotate` (before sizes are profile; the image is first turned upright with `AutoRotate` (before sizes are
+14 -11
View File
@@ -419,18 +419,21 @@ func (c *Cache) Stats(ctx context.Context) (*CacheStats, error) {
return nil, fmt.Errorf("failed to get cache stats: %w", err) return nil, fmt.Errorf("failed to get cache stats: %w", err)
} }
// Count and size the cached source images and processed variants // Count and size the cached source images and processed variants. A
err = c.db.QueryRowContext(ctx, ` // disabled cache holds none, whatever rows an earlier run left.
SELECT (SELECT COUNT(*) FROM source_content) if !c.disabled {
+ (SELECT COUNT(*) FROM variant_content) err = c.db.QueryRowContext(ctx, `
`).Scan(&stats.TotalItems) SELECT (SELECT COUNT(*) FROM source_content)
if err != nil { + (SELECT COUNT(*) FROM variant_content)
c.log.Warn("failed to count cache items for stats", "error", err) `).Scan(&stats.TotalItems)
} if err != nil {
c.log.Warn("failed to count cache items for stats", "error", err)
}
stats.TotalSizeBytes, err = c.UsageBytes(ctx) stats.TotalSizeBytes, err = c.UsageBytes(ctx)
if err != nil { if err != nil {
c.log.Warn("failed to sum cache size for stats", "error", err) c.log.Warn("failed to sum cache size for stats", "error", err)
}
} }
// Compute hit rate as a ratio // Compute hit rate as a ratio
+2 -1
View File
@@ -143,7 +143,8 @@ func (s *Service) Get(ctx context.Context, req *ImageRequest) (*ImageResponse, e
s.log.Error("failed to get cached variant", "key", result.CacheKey, "error", err) s.log.Error("failed to get cached variant", "key", result.CacheKey, "error", err)
// Fall through to re-process // Fall through to re-process
} else { } else {
s.cache.IncrementStats(ctx, true, 0) // Counted also when the request context has ended meanwhile
s.cache.IncrementStats(context.WithoutCancel(ctx), true, 0)
return &ImageResponse{ return &ImageResponse{
Content: reader, Content: reader,