From 618b807b3da191490d8eb63ea1d5a6cd3eeafcb3 Mon Sep 17 00:00:00 2001 From: mkelvers Date: Wed, 8 Apr 2026 16:31:10 +0200 Subject: [PATCH] perf: heavily optimize jikan cache by pre-warming individual anime objects and using 30-day TTLs for completed shows --- internal/jikan/anime.go | 7 ++++++- internal/jikan/client.go | 15 +++++++++++++++ internal/jikan/search.go | 2 ++ internal/jikan/seasons.go | 3 +++ 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/internal/jikan/anime.go b/internal/jikan/anime.go index 5e974df..5497d11 100644 --- a/internal/jikan/anime.go +++ b/internal/jikan/anime.go @@ -19,6 +19,11 @@ func (c *Client) GetAnimeByID(id int) (Anime, error) { return Anime{}, err } - c.setCache(cacheKey, result.Data, time.Hour*24) + ttl := time.Hour * 24 + if result.Data.Status == "Finished Airing" { + ttl = time.Hour * 24 * 30 + } + + c.setCache(cacheKey, result.Data, ttl) return result.Data, nil } diff --git a/internal/jikan/client.go b/internal/jikan/client.go index 77fdf94..bbb1373 100644 --- a/internal/jikan/client.go +++ b/internal/jikan/client.go @@ -72,6 +72,21 @@ func (c *Client) setCache(key string, data interface{}, ttl time.Duration) { }) } +// preWarmAnimeCache extracts individual anime from list responses and caches them +func (c *Client) preWarmAnimeCache(animes []Anime) { + for _, a := range animes { + cacheKey := fmt.Sprintf("anime:%d", a.MalID) + + // Smart TTL: Finished shows rarely change, cache for 30 days. Airing/Upcoming shows cache for 24 hours. + ttl := time.Hour * 24 + if a.Status == "Finished Airing" { + ttl = time.Hour * 24 * 30 + } + + c.setCache(cacheKey, a, ttl) + } +} + // fetchWithRetry provides robust fetching respecting Jikan's strict 3 req/sec rate limit func (c *Client) fetchWithRetry(urlStr string, out interface{}) error { maxRetries := 5 diff --git a/internal/jikan/search.go b/internal/jikan/search.go index 3d814ad..e645b4d 100644 --- a/internal/jikan/search.go +++ b/internal/jikan/search.go @@ -32,6 +32,7 @@ func (c *Client) Search(query string, page int) (SearchResult, error) { HasNextPage: result.Pagination.HasNextPage, } + c.preWarmAnimeCache(result.Data) c.setCache(cacheKey, res, time.Hour*1) return res, nil } @@ -58,6 +59,7 @@ func (c *Client) GetTopAnime(page int) (TopAnimeResult, error) { HasNextPage: result.Pagination.HasNextPage, } + c.preWarmAnimeCache(result.Data) c.setCache(cacheKey, res, time.Hour*1) return res, nil } diff --git a/internal/jikan/seasons.go b/internal/jikan/seasons.go index fae5296..a1a67a4 100644 --- a/internal/jikan/seasons.go +++ b/internal/jikan/seasons.go @@ -34,6 +34,7 @@ func (c *Client) GetSchedule(day string) (ScheduleResult, error) { HasNextPage: result.Pagination.HasNextPage, } + c.preWarmAnimeCache(result.Data) c.setCache(cacheKey, res, time.Hour*1) return res, nil } @@ -76,6 +77,7 @@ func (c *Client) GetSeasonsNow(page int) (TopAnimeResult, error) { HasNextPage: result.Pagination.HasNextPage, } + c.preWarmAnimeCache(result.Data) c.setCache(cacheKey, res, time.Hour*1) return res, nil } @@ -102,6 +104,7 @@ func (c *Client) GetSeasonsUpcoming(page int) (TopAnimeResult, error) { HasNextPage: result.Pagination.HasNextPage, } + c.preWarmAnimeCache(result.Data) c.setCache(cacheKey, res, time.Hour*1) return res, nil }