finish service.zig cleanup

This commit is contained in:
Emil Lerch 2026-03-10 13:40:06 -07:00
parent 7eba504ed8
commit 543be9733e
Signed by: lobo
GPG key ID: A7B62D657EF764F8
3 changed files with 18 additions and 16 deletions

View file

@ -281,7 +281,7 @@ pub fn fmtLargeNum(val: f64) [15]u8 {
/// Get today's date. /// Get today's date.
pub fn todayDate() Date { pub fn todayDate() Date {
const ts = std.time.timestamp(); const ts = std.time.timestamp();
const days: i32 = @intCast(@divFloor(ts, 86400)); const days: i32 = @intCast(@divFloor(ts, std.time.s_per_day));
return .{ .days = days }; return .{ .days = days };
} }

View file

@ -59,6 +59,13 @@ pub fn acquire(self: *RateLimiter) void {
} }
} }
/// Sleep until a token is likely available, with a minimum 2-second floor.
/// Use after receiving a server-side 429 to wait before retrying.
pub fn backoff(self: *RateLimiter) void {
const wait_ns: u64 = @max(self.estimateWaitNs(), 2 * std.time.ns_per_s);
std.Thread.sleep(wait_ns);
}
/// Returns estimated wait time in nanoseconds until a token is available. /// Returns estimated wait time in nanoseconds until a token is available.
/// Returns 0 if a token is available now. /// Returns 0 if a token is available now.
pub fn estimateWaitNs(self: *RateLimiter) u64 { pub fn estimateWaitNs(self: *RateLimiter) u64 {

View file

@ -26,6 +26,7 @@ const Cboe = @import("providers/cboe.zig").Cboe;
const AlphaVantage = @import("providers/alphavantage.zig").AlphaVantage; const AlphaVantage = @import("providers/alphavantage.zig").AlphaVantage;
const alphavantage = @import("providers/alphavantage.zig"); const alphavantage = @import("providers/alphavantage.zig");
const OpenFigi = @import("providers/openfigi.zig"); const OpenFigi = @import("providers/openfigi.zig");
const fmt = @import("format.zig");
const performance = @import("analytics/performance.zig"); const performance = @import("analytics/performance.zig");
pub const DataError = error{ pub const DataError = error{
@ -219,7 +220,7 @@ pub const DataService = struct {
/// the entire history. /// the entire history.
pub fn getCandles(self: *DataService, symbol: []const u8) DataError!FetchResult(Candle) { pub fn getCandles(self: *DataService, symbol: []const u8) DataError!FetchResult(Candle) {
var s = self.store(); var s = self.store();
const today = todayDate(); const today = fmt.todayDate();
// Check candle metadata for freshness (tiny file, no candle deserialization) // Check candle metadata for freshness (tiny file, no candle deserialization)
const meta_result = s.readCandleMeta(symbol); const meta_result = s.readCandleMeta(symbol);
@ -325,7 +326,7 @@ pub const DataService = struct {
/// date has no actual results yet (i.e. results just came out). /// date has no actual results yet (i.e. results just came out).
pub fn getEarnings(self: *DataService, symbol: []const u8) DataError!FetchResult(EarningsEvent) { pub fn getEarnings(self: *DataService, symbol: []const u8) DataError!FetchResult(EarningsEvent) {
var s = self.store(); var s = self.store();
const today = todayDate(); const today = fmt.todayDate();
if (s.read(EarningsEvent, symbol, earningsPostProcess, .fresh_only)) |cached| { if (s.read(EarningsEvent, symbol, earningsPostProcess, .fresh_only)) |cached| {
// Check if any past/today earnings event is still missing actual results. // Check if any past/today earnings event is still missing actual results.
@ -420,7 +421,7 @@ pub const DataService = struct {
const c = candle_result.data; const c = candle_result.data;
if (c.len == 0) return DataError.FetchFailed; if (c.len == 0) return DataError.FetchFailed;
const today = todayDate(); const today = fmt.todayDate();
// As-of-date (end = last candle) // As-of-date (end = last candle)
const asof_price = performance.trailingReturns(c); const asof_price = performance.trailingReturns(c);
@ -706,18 +707,12 @@ pub const DataService = struct {
// Utility // Utility
/// Sleep before retrying after a rate limit error. /// Sleep before retrying after a rate limit error.
/// Uses the provider's rate limiter estimate if available, otherwise a fixed 10s backoff. /// Uses the provider's rate limiter if available, otherwise a fixed 10s backoff.
fn rateLimitBackoff(self: *DataService) void { fn rateLimitBackoff(self: *DataService) void {
const wait_ns: u64 = if (self.td) |*td| if (self.td) |*td| {
@max(td.rate_limiter.estimateWaitNs(), 2 * std.time.ns_per_s) td.rate_limiter.backoff();
else } else {
10 * std.time.ns_per_s; std.Thread.sleep(10 * std.time.ns_per_s);
std.Thread.sleep(wait_ns);
} }
fn todayDate() Date {
const ts = std.time.timestamp();
const days: i32 = @intCast(@divFloor(ts, std.time.s_per_day));
return .{ .days = days };
} }
}; };