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`
- **Storage**: Redis via `Rails.cache` (uses `Gitlab::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_user` method with different access levels
- Current `SafeRequestStore` key already includes this: `"user:#{user&.id}-min_access_level:#{min_access_level}-groups_for_search"`
- Defaults to `GUEST` if not provided
- **`features`** - Can be ignored for caching purposes
- The `features` param is mutually exclusive with `min_access_level` and internally converts to a `min_access_level`
- Since it's converted to `min_access_level`, we only need to cache based on the resolved access level
For `Search::ProjectsFinder`:
- **No parameters** - The `_params` argument is currently unused (placeholder for future)
- Cache key only needs `user_id`
**Redis is appropriate here because:**
1. `Rails.cache` already uses `Gitlab::Redis::Cache` with an 8-hour default TTL
2. The cache instance has key eviction policies configured
3. This is truly cache-like data that can be regenerated if absent
4. 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::SafeRequestStore` caching
- Keep the request-scoped cache for within-request performance
- Add Redis cache to reduce cross-request overhead
- For `GroupsFinder`: Cache separately for each `min_access_level` value
- 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` - Accepts `min_access_level` and `features` params
- `ee/app/finders/search/projects_finder.rb` - Currently no params used
- `ee/lib/search/elastic/concerns/authorization_utils.rb` - Current `SafeRequestStore` usage with `min_access_level`
issue