Merge branch 'codex/edb6' into integrate-codex-work

# Conflicts:
#	integrations/jikan/client_test.go
This commit is contained in:
2026-06-21 17:20:46 +02:00
7 changed files with 173 additions and 1 deletions

View File

@@ -22,6 +22,7 @@ func NewStore(queries db.Querier, metrics *observability.Metrics) *Store {
func (s *Store) Get(parentCtx context.Context, key string, out any) bool {
ctx, cancel := context.WithTimeout(parentCtx, 2*time.Second)
defer cancel()
defer s.observeStats(parentCtx)
data, err := s.db.GetJikanCache(ctx, key)
if err != nil {
@@ -42,6 +43,7 @@ func (s *Store) Get(parentCtx context.Context, key string, out any) bool {
func (s *Store) GetStale(parentCtx context.Context, key string, out any) bool {
ctx, cancel := context.WithTimeout(parentCtx, 2*time.Second)
defer cancel()
defer s.observeStats(parentCtx)
data, err := s.db.GetJikanCacheStale(ctx, key)
if err != nil {
@@ -62,6 +64,7 @@ func (s *Store) GetStale(parentCtx context.Context, key string, out any) bool {
func (s *Store) Set(parentCtx context.Context, key string, data any, ttl time.Duration) {
ctx, cancel := context.WithTimeout(parentCtx, 2*time.Second)
defer cancel()
defer s.observeStats(parentCtx)
bytes, err := json.Marshal(data)
if err != nil {
@@ -84,3 +87,22 @@ func (s *Store) Set(parentCtx context.Context, key string, data any, ttl time.Du
)
}
}
func (s *Store) observeStats(parentCtx context.Context) {
ctx, cancel := context.WithTimeout(parentCtx, 2*time.Second)
defer cancel()
stats, err := s.db.GetJikanCacheStats(ctx)
if err != nil {
observability.LogJSON(
observability.LogLevelWarn,
"jikan_cache_stats",
"jikan",
"",
nil,
err,
)
return
}
s.metrics.ObserveJikanCacheStats(stats.TotalRows, stats.ExpiredRows, stats.OldestExpiresAtSeconds)
}

View File

@@ -112,6 +112,33 @@ func TestLoadCachedRandomPoolIgnoresExpiredAnimeCache(t *testing.T) {
}
}
func TestGetJikanCacheStatsCountsRowsAndExpiry(t *testing.T) {
sqlDB := newTestCacheDB(t)
defer func() {
if err := sqlDB.Close(); err != nil {
t.Errorf("close sqlite: %v", err)
}
}()
oldest := time.Date(2026, 6, 20, 12, 0, 0, 0, time.UTC)
insertCachedResponse(t, sqlDB, "expired", TopAnimeResponse{Data: []Anime{{MalID: 1}}}, oldest)
insertCachedResponse(t, sqlDB, "fresh", TopAnimeResponse{Data: []Anime{{MalID: 2}}}, time.Now().Add(time.Hour))
stats, err := db.New(sqlDB).GetJikanCacheStats(context.Background())
if err != nil {
t.Fatalf("GetJikanCacheStats: %v", err)
}
if stats.TotalRows != 2 {
t.Fatalf("TotalRows = %d, want 2", stats.TotalRows)
}
if stats.ExpiredRows != 1 {
t.Fatalf("ExpiredRows = %d, want 1", stats.ExpiredRows)
}
if stats.OldestExpiresAtSeconds != oldest.Unix() {
t.Fatalf("OldestExpiresAtSeconds = %d, want %d", stats.OldestExpiresAtSeconds, oldest.Unix())
}
}
func newTestCacheDB(t *testing.T) *sql.DB {
t.Helper()
ctx := context.Background()