diff options
| author | Paul Buetow <paul@buetow.org> | 2026-06-19 08:15:28 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-06-19 08:15:28 +0300 |
| commit | 682a413db516e1a0201e8fea41e706a7666391d6 (patch) | |
| tree | 614566bce20aacd4935aa81fd9c49aca523a2113 | |
| parent | a80ad2b4691d0df63f68c6977ee18444e7bb752f (diff) | |
ik0 remove mutable clock holders
| -rw-r--r-- | internal/hexaicli/cache.go | 11 | ||||
| -rw-r--r-- | internal/stats/stats.go | 12 |
2 files changed, 7 insertions, 16 deletions
diff --git a/internal/hexaicli/cache.go b/internal/hexaicli/cache.go index 742ffce..127c7f4 100644 --- a/internal/hexaicli/cache.go +++ b/internal/hexaicli/cache.go @@ -17,17 +17,12 @@ const cliResponseCacheTTL = 24 * time.Hour // responseCache carries the injectable dependencies for the on-disk CLI // response cache. The only dependency is the clock used to stamp entries and -// decide expiry. Production code uses defaultResponseCache (backed by -// time.Now); tests construct a responseCache with a fake clock to exercise TTL -// expiry without sleeping. +// decide expiry. Production wrappers construct it with time.Now; tests can use +// a fake clock to exercise TTL expiry without sleeping. type responseCache struct { now func() time.Time } -// defaultResponseCache is the production cache used by the package-level -// lookup/store wrappers. It reads the real wall clock. -var defaultResponseCache = responseCache{now: time.Now} - // cacheNowContextKey carries an injected clock through the request context so // the cache TTL logic can be driven deterministically (e.g. in tests) without // mutating package state. @@ -45,7 +40,7 @@ func responseCacheFromContext(ctx context.Context) responseCache { if now, ok := ctx.Value(cacheNowContextKey{}).(func() time.Time); ok && now != nil { return responseCache{now: now} } - return defaultResponseCache + return responseCache{now: time.Now} } type cliResponseCacheKey struct { diff --git a/internal/stats/stats.go b/internal/stats/stats.go index 65d1b2d..16327f6 100644 --- a/internal/stats/stats.go +++ b/internal/stats/stats.go @@ -31,16 +31,12 @@ var windowSeconds int64 = int64(defaultWindow.Seconds()) // engine carries the injectable dependencies for stats operations. The only // dependency today is the clock source for event timestamps and pruning -// cutoffs. Production code uses defaultEngine (backed by time.Now); tests -// construct an engine with a fake clock to control time without sleeping. +// cutoffs. Production wrappers construct it with time.Now; tests can use a fake +// clock to control time without sleeping. type engine struct { now func() time.Time } -// defaultEngine is the production engine used by the package-level Update and -// TakeSnapshot wrappers. It reads the real wall clock. -var defaultEngine = engine{now: time.Now} - // SetWindow sets the sliding window used for pruning and aggregation. func SetWindow(d time.Duration) { if d < time.Second { @@ -115,7 +111,7 @@ func (s Snapshot) ScopeRPM(provider, model string) float64 { // Update appends one event and prunes old entries under lock, using the // production clock. It delegates to engine.update. func Update(ctx context.Context, provider, model string, sentBytes, recvBytes int) error { - return defaultEngine.update(ctx, provider, model, sentBytes, recvBytes) + return engine{now: time.Now}.update(ctx, provider, model, sentBytes, recvBytes) } // update appends one event and prunes old entries under lock. @@ -232,7 +228,7 @@ func writeStatsFileAtomic(dir, path string, sf *File) error { // TakeSnapshot reads the stats file and aggregates events within the stored // window, using the production clock. It delegates to engine.takeSnapshot. func TakeSnapshot() (Snapshot, error) { - return defaultEngine.takeSnapshot() + return engine{now: time.Now}.takeSnapshot() } // takeSnapshot reads the stats file and aggregates events within the stored |
