Skip to content

Caching and request deduplication #2594

Closed

Description

@magrhino

Parent: #2592 — Reduce Hardcover API usage and support daily quotas

Pre-flight

  • Searched existing issues; related reports are referenced by the parent.
  • Checked the roadmap; this cache/deduplication scope is not already planned there.

Problem

SearchAuthorsWithOutcome and SearchBooks in internal/metadata/aggregator.go fan out to providers without server-side search caching. Metadata cache get/fetch/set sequences do not combine identical concurrent misses. GetEditions and GetEditionsFromProvider use different keys even when they resolve to the same Hardcover book.

The existing 24-hour cache is bounded but in memory, so restarts discard it. These redundant calls consume a plan-dependent daily allowance: see Hardcover Supporter.

Proposed solution

  • Add bounded, short-lived provider-level search caching so ordinary searches and enrichment can reuse equivalent successful responses. Include query options and any relevant account/provider configuration in cache identity.
  • Combine identical in-flight requests so concurrent misses perform one upstream fetch. Preserve cancellation semantics and avoid sharing mutable cached results unsafely.
  • Resolve the provider before canonicalizing edition cache keys. Unify equivalent routed and explicit-provider lookups without confusing numeric IDs with slugs or mixing providers/accounts.
  • Reuse existing metadata caching where practical. Evaluate persisted edition freshness for restart reuse; preserve an explicit refresh path and avoid treating partially populated local editions as a complete upstream snapshot.
  • Cache legitimate empty results according to policy, but do not cache rate-limit/auth/network failures as successful empty data. Invalidate affected state on configuration changes.

Acceptance criteria

  • Repeated equivalent searches and concurrent identical misses reduce counted upstream requests.
  • Equivalent edition lookup routes share cached results; different providers, identities, and account scopes remain isolated.
  • Cache bounds, expiry, cancellation, configuration changes, empty results, and failures have focused coverage.
  • Existing search ranking, enrichment, edition completeness, and explicit refresh behavior are preserved.

Additional context

Covers review items 3 + 5. Coordinate with daily request accounting so cache hits are not charged locally. Related #2173 concerns skipping unchanged ABS items and is not replaced by this cache work.

Activity

  1. vavallee commented on Sep 26, 2026

    @vavallee
    Owner

    Keeping this one, with #2592 now closed as a parent. The core claims all still verify: there is no search caching at either level, no singleflight anywhere in the tree, and GetEditions and GetEditionsFromProvider still use different cache key namespaces.

    PR #2615 needs a rebase rather than a merge. It is around 70 commits behind, reports CONFLICTING, and it touches two files that moved underneath it: aggregator_enrichment.go, which #2767 changed two days ago when field locks landed, and aggregator.go, where #2641 changed GetBookByISBNWithOutcome's signature.

    This is the semantic conflict shape that has broken main here before, where two individually green PRs on one file produce a broken merge. So the rebased branch wants a build and a full test run against merged main, not a green check on a stale base.

    One item struck from the follow up list: #2611 fixed manual author refresh fetching past the 24 hour cache, which this PR had explicitly deferred to #2601. That is done.

    Ordering note carried from the parent: #2593 lands first, because this builds on the quota carrying client.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions