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.

feat: persist timing data to /data volume

saves timing stats to /data/timing.bin every 100 requests.
loads on first request after restart. survives deploys.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

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

zzstoatzz 00f81604 0c7d7822

+56
+56
backend/src/timing.zig
··· 14 14 15 15 const SAMPLE_COUNT = 1000; 16 16 const ENDPOINT_COUNT = @typeInfo(Endpoint).@"enum".fields.len; 17 + const PERSIST_PATH = "/data/timing.bin"; 18 + const PERSIST_INTERVAL = 100; // save every N records 17 19 18 20 /// per-endpoint latency buffer 19 21 const LatencyBuffer = struct { ··· 42 44 43 45 var buffers: [ENDPOINT_COUNT]LatencyBuffer = [_]LatencyBuffer{.{}} ** ENDPOINT_COUNT; 44 46 var mutex: std.Thread.Mutex = .{}; 47 + var records_since_persist: u32 = 0; 48 + var initialized: bool = false; 45 49 46 50 /// record a request latency (call after request completes) 47 51 pub fn record(endpoint: Endpoint, start_time: i64) void { ··· 50 54 51 55 mutex.lock(); 52 56 defer mutex.unlock(); 57 + 58 + if (!initialized) { 59 + initialized = true; 60 + loadLocked(); 61 + } 62 + 53 63 buffers[@intFromEnum(endpoint)].record(elapsed_us); 64 + 65 + // persist periodically 66 + records_since_persist += 1; 67 + if (records_since_persist >= PERSIST_INTERVAL) { 68 + records_since_persist = 0; 69 + persistLocked(); 70 + } 71 + } 72 + 73 + fn loadLocked() void { 74 + const file = std.fs.openFileAbsolute(PERSIST_PATH, .{}) catch return; 75 + defer file.close(); 76 + 77 + // read entire file at once (small file, ~16KB per endpoint) 78 + var file_buf: [ENDPOINT_COUNT * (@sizeOf([SAMPLE_COUNT]u32) + @sizeOf(usize) * 2 + @sizeOf(u64))]u8 = undefined; 79 + const bytes_read = file.readAll(&file_buf) catch return; 80 + if (bytes_read != file_buf.len) return; // incomplete file 81 + 82 + var offset: usize = 0; 83 + for (&buffers) |*buf| { 84 + const samples_size = @sizeOf([SAMPLE_COUNT]u32); 85 + buf.samples = std.mem.bytesToValue([SAMPLE_COUNT]u32, file_buf[offset..][0..samples_size]); 86 + offset += samples_size; 87 + 88 + buf.count = std.mem.readInt(usize, file_buf[offset..][0..@sizeOf(usize)], .little); 89 + offset += @sizeOf(usize); 90 + 91 + buf.head = std.mem.readInt(usize, file_buf[offset..][0..@sizeOf(usize)], .little); 92 + offset += @sizeOf(usize); 93 + 94 + buf.total_count = std.mem.readInt(u64, file_buf[offset..][0..@sizeOf(u64)], .little); 95 + offset += @sizeOf(u64); 96 + } 97 + } 98 + 99 + fn persistLocked() void { 100 + const file = std.fs.createFileAbsolute(PERSIST_PATH, .{}) catch return; 101 + defer file.close(); 102 + 103 + // write all buffers 104 + for (buffers) |buf| { 105 + file.writeAll(std.mem.asBytes(&buf.samples)) catch return; 106 + file.writeAll(std.mem.asBytes(&buf.count)) catch return; 107 + file.writeAll(std.mem.asBytes(&buf.head)) catch return; 108 + file.writeAll(std.mem.asBytes(&buf.total_count)) catch return; 109 + } 54 110 } 55 111 56 112 /// get stats for a specific endpoint