Add short lived cache for Search::GroupsFinder and Search::ProjectsFinder
Problem
The Search::GroupsFinder and Search::ProjectsFinder classes are currently called multiple times during search operations, particularly in advanced search scenarios. While they use Gitlab::SafeRequestStore for request-scoped caching (as seen in ee/lib/search/elastic/concerns/authorization_utils.rb), this cache only persists for a single request. Subsequent requests from the same user must recompute the authorized groups and projects, which can be expensive operations.
Proposal
Implement a short-lived Redis cache (5-10 minutes TTL) for these finders to reduce repeated authorization queries across multiple requests from the same user.
Cache specifications:
- Duration: 5-10 minutes TTL
-
Cache key format:
- Groups:
search_user:{user_id}:min_access_level:{level}:groups - Projects:
search_user:{user_id}:projects
- Groups:
-
Storage: Redis via
Rails.cache(usesGitlab::Redis::Cache) - Scope: Per-user basis
- Invalidation: Time-based expiration (TTL)
Implementation considerations
Parameters to include in cache key:
For Search::GroupsFinder:
-
min_access_level- MUST be included in cache key as it affects results- Used in
groups_for_usermethod with different access levels - Current
SafeRequestStorekey already includes this:"user:#{user&.id}-min_access_level:#{min_access_level}-groups_for_search" - Defaults to
GUESTif not provided
- Used in
-
features- Can be ignored for caching purposes- The
featuresparam is mutually exclusive withmin_access_leveland internally converts to amin_access_level - Since it's converted to
min_access_level, we only need to cache based on the resolved access level
- The
For Search::ProjectsFinder:
-
No parameters - The
_paramsargument is currently unused (placeholder for future) - Cache key only needs
user_id
Redis is appropriate here because:
-
Rails.cachealready usesGitlab::Redis::Cachewith an 8-hour default TTL - The cache instance has key eviction policies configured
- This is truly cache-like data that can be regenerated if absent
- The 5-10 minute TTL is much shorter than the default, reducing staleness concerns
Caching strategy:
- Layer the Redis cache on top of the existing
Gitlab::SafeRequestStorecaching - Keep the request-scoped cache for within-request performance
- Add Redis cache to reduce cross-request overhead
- For
GroupsFinder: Cache separately for eachmin_access_levelvalue - For
ProjectsFinder: Single cache per user (no parameter variations)
Cache invalidation considerations:
- Short TTL (5-10 minutes) provides a reasonable balance between performance and data freshness
- User permissions don't change frequently enough to require immediate invalidation
- Acceptable for search results to reflect permissions up to 10 minutes old
Feature flag consideration:
- This should be implemented behind a derisk feature flag (e.g.,
search_finders_redis_cache) - Allows gradual rollout and monitoring of Redis memory impact
- Enables quick rollback if caching causes unexpected authorization issues or memory pressure
- Can be enabled per-group or percentage-based rollout to validate behavior
Related code
-
ee/app/finders/search/groups_finder.rb- Acceptsmin_access_levelandfeaturesparams -
ee/app/finders/search/projects_finder.rb- Currently no params used -
ee/lib/search/elastic/concerns/authorization_utils.rb- CurrentSafeRequestStoreusage withmin_access_level