Skip to content

[PM-32068] - Org Ability Extended Cache#7443

Open
jrmccannon wants to merge 3 commits intomainfrom
jmccannon/ac/pm-32068-org-ability-cache
Open

[PM-32068] - Org Ability Extended Cache#7443
jrmccannon wants to merge 3 commits intomainfrom
jmccannon/ac/pm-32068-org-ability-cache

Conversation

@jrmccannon
Copy link
Copy Markdown
Contributor

@jrmccannon jrmccannon commented Apr 10, 2026

🎟️ Tracking

PM-32068

📔 Objective

This implements retrieving the org ability record via the Extended Cache (fusion cache). This will be used instead of the in memory cache in order to reduce load on the org ability database table and solve the issue with servicebus.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 10, 2026

Logo
Checkmarx One – Scan Summary & Details8da31fba-6e2d-4750-a741-f6b176c0d645

Great job! No new security vulnerabilities introduced in this pull request

@jrmccannon
Copy link
Copy Markdown
Contributor Author

@claude be kind

@claude
Copy link
Copy Markdown
Contributor

claude bot commented Apr 10, 2026

Claude finished @jrmccannon's task in 1m 2s —— View job


Kind Review of Your PR

  • Read all changed files
  • Analyze architecture and patterns
  • Provide feedback

Hey Jared! Nice work on this one. The overall design is clean and well thought out. Here are my thoughts:


What I really like

  • Clean separation of concerns — The new IOrganizationAbilityCacheService interface is focused and minimal. Three methods, each doing exactly one thing. That's great API design.

  • Feature flag routing — Using FeatureFlagKeys.OrgAbilityExtendedCache to gradually roll this out via FeatureRoutedCacheService is a solid approach. It lets you safely migrate from in-memory to FusionCache without a big-bang switch.

  • Thorough test coverage — The tests for both ExtendedOrganizationAbilityCacheService and the updated FeatureRoutedCacheService are comprehensive. You're covering flag-on, flag-off, null returns, the BaseUpsert/BaseDelete paths, the InvalidOperationException fallback, duplicate IDs, missing IDs — really nice coverage.

  • Cache key design — Using org-ability:{guid:N} in OrganizationAbilityCacheConstants is clean and descriptive. Centralizing the key format in a constants class is the right call.

  • Primary constructor usage — The primary constructors on both ExtendedOrganizationAbilityCacheService and FeatureRoutedCacheService keep things concise.

A couple of small observations

  1. Scoped vs Singleton lifetime (ServiceCollectionExtensions.cs:299, Startup.cs:60) — ExtendedOrganizationAbilityCacheService is registered as Scoped, while the in-memory cache services it sits alongside are Singleton. This is totally fine since FusionCache itself manages its own lifetime, but worth keeping in mind if anyone ever injects per-request state into the cache service later.

  2. GetOrganizationAbilitiesAsync(IEnumerable<Guid>) still uses in-memory (FeatureRoutedCacheService.cs:41-48) — The bulk/batch fetch still goes through the in-memory path even when the flag is on. I imagine this is intentional for now (since FusionCache is per-key), but just flagging it for visibility in case you plan to migrate those callers later too.

Overall this is a well-structured, incremental improvement. The FusionCache integration looks correct, the feature flag gives you a safe rollout path, and the tests give good confidence. Nice job! 👍


@codecov
Copy link
Copy Markdown

codecov bot commented Apr 10, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 58.68%. Comparing base (f2141b9) to head (4737558).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #7443      +/-   ##
==========================================
+ Coverage   58.66%   58.68%   +0.01%     
==========================================
  Files        2066     2068       +2     
  Lines       91089    91127      +38     
  Branches     8106     8111       +5     
==========================================
+ Hits        53440    53478      +38     
  Misses      35740    35740              
  Partials     1909     1909              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@jrmccannon jrmccannon marked this pull request as ready for review April 10, 2026 17:28
@jrmccannon jrmccannon requested review from a team as code owners April 10, 2026 17:28
@jrmccannon jrmccannon requested a review from eliykat April 10, 2026 17:28
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BuildCacheKeyForOrganizationAbility isn't a constant :P and I think there's little benefit to being in its own class - I suggest these are private properties in the cache service itself.

Comment on lines 41 to 48
public async Task<IDictionary<Guid, OrganizationAbility>> GetOrganizationAbilitiesAsync(IEnumerable<Guid> orgIds)
{
var allOrganizationAbilities = await inMemoryApplicationCacheService.GetOrganizationAbilitiesAsync();
return orgIds
.Distinct()
.Where(allOrganizationAbilities.ContainsKey)
.ToDictionary(id => id, id => allOrganizationAbilities[id]);
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missed this one. Fwiw, I don't think there's a bulk interface for FusionCache - this is for convenience only. It should have a corresponding interface on the new cache service, which would just await Task.WhenAll individual cache fetches.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is being covered with this ticket

services.AddScoped<IApplicationCacheService, FeatureRoutedCacheService>();
services.AddExtendedCache(OrganizationAbilityCacheConstants.CacheName, globalSettings);
services.AddScoped<IOrganizationAbilityCacheService, ExtendedOrganizationAbilityCacheService>();

Copy link
Copy Markdown
Member

@eliykat eliykat Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better not to expose this at the top level here. Can we have a services extension method - e.g. AddOrganizationAbilityCache - which registers both? Similar to how our commands/queries/handlers are registered.

Copy link
Copy Markdown
Member

@eliykat eliykat Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not a blocker, but I'm not sure of the value of these tests. The class is extremely thin, there's not much to test here by design, and these tests either use mocks or assert against the same prod code that you're testing (i.e. BuildCacheKeyForOrganizationAbility). Consider deleting them and/or relying on integration tests instead.

@jrmccannon jrmccannon force-pushed the jmccannon/ac/pm-32068-org-ability-cache branch from 9ffa092 to 4737558 Compare April 14, 2026 13:45
…with specific endpoints tested. moved registration to ext method
@jrmccannon jrmccannon requested a review from eliykat April 14, 2026 15:03
@sonarqubecloud
Copy link
Copy Markdown

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants