search for standard sites pub-search.waow.tech
search zig blog atproto
11
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix: /stats endpoint also returned zeros — cache init race

getStatsLocal() required stats_buffer cache to be initialized, but
refreshCachedStats was only called at startup (which could fail) and
when search deltas were non-zero. If init failed and no searches
happened, cache stayed uninitialized, /stats returned all zeros.

- always refresh cache in sync loop (not just when deltas exist)
- getStatsLocal() no longer fails when cache isn't initialized — returns
local counts with 0 for cached fields instead of aborting entirely

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

zzstoatzz 511d29ef 35a7f427

+10 -10
+3 -2
backend/src/metrics/buffer.zig
··· 145 145 // sync stats if any changed 146 146 if (searches != 0 or errors != 0 or cache_hits != 0 or cache_misses != 0) { 147 147 syncStatsDelta(c, searches, errors, cache_hits, cache_misses); 148 - // refresh cache after writing (base values changed) 149 - refreshCachedStats(c); 150 148 } 149 + 150 + // always refresh cache (recovers from init failure, picks up external changes) 151 + refreshCachedStats(c); 151 152 152 153 // sync popular searches 153 154 syncPopularSearches(c);
+7 -8
backend/src/metrics/stats.zig
··· 55 55 } 56 56 57 57 fn getStatsLocal(local: *db.LocalDb) !Stats { 58 - // use cached stats from stats_buffer (instant, no Turso round-trip) 59 - const cached = stats_buffer.getCachedStats() orelse return error.CacheNotInitialized; 60 - 61 58 // get document counts from local (fast) 62 59 var rows = try local.query( 63 60 \\SELECT ··· 68 65 defer rows.deinit(); 69 66 const row = rows.next() orelse return error.NoRows; 70 67 68 + // use cached stats from stats_buffer if available (searches, errors, etc.) 69 + const cached = stats_buffer.getCachedStats(); 71 70 return .{ 72 71 .documents = row.int(0), 73 72 .publications = row.int(1), 74 73 .embeddings = row.int(2), 75 - .searches = cached.searches, 76 - .errors = cached.errors, 77 - .started_at = cached.started_at, 78 - .cache_hits = cached.cache_hits, 79 - .cache_misses = cached.cache_misses, 74 + .searches = if (cached) |c| c.searches else 0, 75 + .errors = if (cached) |c| c.errors else 0, 76 + .started_at = if (cached) |c| c.started_at else 0, 77 + .cache_hits = if (cached) |c| c.cache_hits else 0, 78 + .cache_misses = if (cached) |c| c.cache_misses else 0, 80 79 }; 81 80 } 82 81