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

fix: remove turso client mutex — use per-request http clients

the shared mutex on Client.zig serialized ALL turso requests across
threads. during full sync, this blocked search queries from reaching
turso even when local sqlite wasn't ready yet.

now each request creates its own http client, so sync and search
can hit turso concurrently.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+10 -12
+10 -12
backend/src/db/Client.zig
··· 27 27 allocator: Allocator, 28 28 url: []const u8, 29 29 token: []const u8, 30 - mutex: std.Thread.Mutex = .{}, 31 - http_client: http.Client, 32 30 33 31 pub fn init(allocator: Allocator) !Client { 34 32 const url = std.posix.getenv("TURSO_URL") orelse { ··· 52 50 .allocator = allocator, 53 51 .url = host, 54 52 .token = token, 55 - .http_client = .{ .allocator = allocator }, 56 53 }; 57 54 } 58 55 59 56 pub fn deinit(self: *Client) void { 60 - self.http_client.deinit(); 57 + _ = self; 61 58 } 62 59 63 60 pub fn query(self: *Client, comptime sql: []const u8, args: anytype) !Result { ··· 123 120 }); 124 121 defer span.end(); 125 122 126 - self.mutex.lock(); 127 - defer self.mutex.unlock(); 128 - 129 123 var url_buf: [URL_BUF_SIZE]u8 = undefined; 130 124 const url = std.fmt.bufPrint(&url_buf, "https://{s}/v2/pipeline", .{self.url}) catch 131 125 return error.UrlTooLong; ··· 140 134 var response_body: std.Io.Writer.Allocating = .init(self.allocator); 141 135 errdefer response_body.deinit(); 142 136 143 - const res = self.http_client.fetch(.{ 137 + // per-request http client — no shared mutex needed 138 + var hc: http.Client = .{ .allocator = self.allocator }; 139 + defer hc.deinit(); 140 + 141 + const res = hc.fetch(.{ 144 142 .location = .{ .url = url }, 145 143 .method = .POST, 146 144 .headers = .{ ··· 177 175 }); 178 176 defer span.end(); 179 177 180 - self.mutex.lock(); 181 - defer self.mutex.unlock(); 182 - 183 178 var url_buf: [URL_BUF_SIZE]u8 = undefined; 184 179 const url = std.fmt.bufPrint(&url_buf, "https://{s}/v2/pipeline", .{self.url}) catch 185 180 return error.UrlTooLong; ··· 194 189 var response_body: std.Io.Writer.Allocating = .init(self.allocator); 195 190 errdefer response_body.deinit(); 196 191 197 - const res = self.http_client.fetch(.{ 192 + var hc: http.Client = .{ .allocator = self.allocator }; 193 + defer hc.deinit(); 194 + 195 + const res = hc.fetch(.{ 198 196 .location = .{ .url = url }, 199 197 .method = .POST, 200 198 .headers = .{