From 342bd096da93f96c7e6de9b4d8e777fa1a35ec1e Mon Sep 17 00:00:00 2001 From: mkelvers Date: Thu, 4 Jun 2026 11:28:13 +0200 Subject: [PATCH] feat: stale-while-revalidate cache for watch order --- integrations/jikan/relations.go | 46 +++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/integrations/jikan/relations.go b/integrations/jikan/relations.go index faded35..9cd68d6 100644 --- a/integrations/jikan/relations.go +++ b/integrations/jikan/relations.go @@ -43,15 +43,8 @@ func relationCacheKey(id int) string { return fmt.Sprintf("relations:watch-order:%d", id) } -// getWatchOrder fetches watch order from chiaki, caches result for 24h. -func (c *Client) getWatchOrder(ctx context.Context, id int) (watchorder.WatchOrderResult, error) { +func (c *Client) refreshWatchOrder(ctx context.Context, id int) (watchorder.WatchOrderResult, error) { cacheKey := relationCacheKey(id) - - var cached watchorder.WatchOrderResult - if c.getCache(ctx, cacheKey, &cached) { - return cached, nil - } - watchOrderURL := fmt.Sprintf(chiakiWatchOrderURL, id) requestCtx, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() @@ -109,6 +102,37 @@ func (c *Client) getWatchOrder(ctx context.Context, id int) (watchorder.WatchOrd return result, nil } +func (c *Client) refreshWatchOrderAsync(id int) { + c.runAsyncRefresh(func(ctx context.Context) { + _, _ = c.refreshWatchOrder(ctx, id) + }) +} + +// getWatchOrder fetches watch order from chiaki, caches result for 24h. +func (c *Client) getWatchOrder(ctx context.Context, id int) (watchorder.WatchOrderResult, error) { + cacheKey := relationCacheKey(id) + + var cached watchorder.WatchOrderResult + if c.getCache(ctx, cacheKey, &cached) { + return cached, nil + } + + if c.getStaleCache(ctx, cacheKey, &cached) { + c.refreshWatchOrderAsync(id) + return cached, nil + } + + result, err := c.refreshWatchOrder(ctx, id) + if err != nil { + if c.getStaleCache(ctx, cacheKey, &cached) { + return cached, nil + } + return watchorder.WatchOrderResult{}, err + } + + return result, nil +} + // currentOnlyRelation returns just the current anime when watch order lookup fails. func (c *Client) currentOnlyRelation(ctx context.Context, id int) ([]RelationEntry, error) { currentAnime, err := c.GetAnimeByID(ctx, id) @@ -230,3 +254,9 @@ func (c *Client) GetFullRelations(ctx context.Context, id int) ([]RelationEntry, return relations, nil } + +func (c *Client) WarmFullRelations(id int) { + c.runAsyncRefresh(func(ctx context.Context) { + _, _ = c.GetFullRelations(ctx, id) + }) +}