8000 feat(cache): add LRU and TTL implementations and optional REST fallback by Saiop68 · Pull Request #635 · disgoorg/disgo · GitHub
[go: up one dir, main page]

Skip to content

feat(cache): add LRU and TTL implementations and optional REST fallback - #635

Open
Saiop68 wants to merge 7 commits into
disgoorg:masterfrom
Saiop68:feat/lru-ttl-cache
Open

Saiop68 wants to merge 7 commits into
disgoorg:masterfrom
Saiop68:feat/lru-ttl-cache

Conversation

@Saiop68
@Saiop68 Saiop68 commented Oct 23, 2026 •
Copy link
Copy Markdown
Contributor

Overview

This PR adds thread-safe LRU (Least Recently Used) and TTL (Time-To-Live) cache implementations for cache.Cache[T] and cache.GroupedCache[T], as well as an optional REST fallback layer for cache.Caches.


Implementations

1. LRUCache[T any] (implements Cache[T])

  • O(1) LRU eviction using doubly-linked list sentinel nodes (head/tail) and hash map lookup.
  • Optional TTL expiration via WithLRUTTL(duration). Expired entities are lazily evicted on access and filtered from iterations.
  • Eviction callback via WithLRUOnEvict(func(id snowflake.ID, entity T)).
  • Iterators: Implements standard Go 1.23 All() iter.Seq[T] skipping expired entries.
  • Helper constructor: NewTTLCache(...) for pure TTL-based caches without capacity limits.

2. GroupedLRUCache[T any] (implements GroupedCache[T])

  • Per-group LRU capacity (maxItemsPerGroup) for grouped entities (e.g. guild members or channel messages).
  • Group-level LRU eviction (WithGroupedLRUMaxGroups(maxGroups)) to bound the total number of cached groups.
  • Optional TTL expiration via WithGroupedLRUTTL(duration).
  • Group lifecycle management: GroupRemove(groupID), GroupRemoveIf(groupID, filter).
  • Iterators: Implements standard All() iter.Seq2[snowflake.ID, T] and GroupAll(groupID) iter.Seq[T].
  • Helper constructor: NewGroupedTTLCache(...).

3. RestFallbackCaches (implements Caches)

  • REST Fallback Wrapper: Optional decorator wrapping cache.Caches that fetches missing entities on cache misses via rest.Rest and populates them into the underlying cache.
  • Configurable Flags: RestFallbackFlags allows granular control over which entities fallback to REST (e.g. RestFallbackFlagMembers, RestFallbackFlagRoles, etc.).
  • Disabled by default: Prevents unexpected REST traffic unless explicitly opted in.
  • Constructors & Options:
    • cache.NewRestFallbackCaches(caches, rest, flags)
    • cache.WithRestFallback(rest, flags...) option for cache.New(...)
    • bot.WithRestFallback(flags...) top-level option for disgo.New(...)

Tests

  • Added cache/lru_cache_test.go with 10 unit tests for LRU eviction, TTL expiration, group management, and multi-goroutine concurrency.
  • Added cache/rest_fallback_test.go testing cache miss fallback, subsequent cache hits, and disabled flags.

@Saiop68 Saiop68 reopened this Oct 23, 2026
@Saiop68 Saiop68 changed the title feat(cache): add LRU and TTL implementations for Cache and GroupedCache feat(cache): add LRU and TTL implementations and optional REST fallback Oct 23, 2026
8000
…lication, and expand test suite

- Execute eviction callbacks strictly outside mutex locks to allow safe reentrant operations\n- Yield snapshots in iterators to prevent deadlocks when mutating cache during iteration\n- Add singleflight request coalescing to REST fallback wrapper to prevent concurrent miss request storms\n- Handle non-guild channel types gracefully and document GuildChannel cache limitation\n- Prevent double-wrapping in NewRestFallbackCaches\n- Invoke eviction callbacks consistently on Remove and GroupRemove\n- Document TTL <= 0 and Put expiration refresh semantics\n- Add comprehensive regression and concurrency unit tests
@Saiop68 Saiop68 closed this Nov 6, 2026
@Saiop68 Saiop68 reopened this Nov 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

1 participant

0