- Notifications
You must be signed in to change notification settings - Fork1.5k
Use extended cache for caching integration configuration details#6650
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
base:main
Are you sure you want to change the base?
Use extended cache for caching integration configuration details#6650
Uh oh!
There was an error while loading.Please reload this page.
Conversation
claudebot commentedNov 26, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Claude finished@brant-livefront's task ——View job Code Review CompleteI've completed a comprehensive review of this PR. Below are my findings organized by severity. SummaryThis PR successfully migrates event integration configuration caching from a custom in-memory implementation to the extended cache framework. The migration provides significant benefits: stampede protection, Redis-backed L2 caching, cache invalidation via backplane, and longer TTLs. The implementation is generally solid with good test coverage for the new features. However, there isone critical bug that must be fixed before merging, along with several other issues requiring attention. Critical IssuesFinding 1: Incorrect JOIN logic produces Cartesian product (STILL UNRESOLVED from previous review)
This query contains redundant and incorrect JOIN syntax that will produce incorrect results: joinoiin dbContext.OrganizationIntegrations on oic.OrganizationIntegrationIdequalsoi.Idinto oioicfrom oiindbContext.OrganizationIntegrations Line 22 creates a LEFT JOIN but never uses the result ( Required fix: varquery=fromoicindbContext.OrganizationIntegrations joinoiindbContext.OrganizationIntegrations onoic.OrganizationIntegrationId equalsoi.Idwhereoi.OrganizationId==_organizationId&&oi.Type==_integrationType&&oic.EventType== _eventType This matches the correct pattern used in Minor IssuesFinding 2: Potential cache invalidation race condition in configuration updates
When updating a configuration, the code invalidates the cache using the OLD varnewConfiguration=model.ToOrganizationIntegrationConfiguration(configuration);awaitintegrationConfigurationRepository.ReplaceAsync(newConfiguration);awaitcache.RemoveAsync(EventIntegrationsCacheConstants.BuildCacheKeyForOrganizationIntegrationConfigurationDetails(organizationId:organizationId,integrationType:integration.Type,eventType:configuration.EventType// ← Using OLD EventType)); Suggested fix: Invalidate both the old and new event type cache entries when they differ: // Invalidate old cache entryawaitcache.RemoveAsync(...,eventType:configuration.EventType);// If EventType changed, also invalidate new cache entryif(newConfiguration.EventType!=configuration.EventType){awaitcache.RemoveAsync(...,eventType:newConfiguration.EventType);} Finding 3: Cache invalidation logic inconsistency between Integration and Configuration controllers
The
The comment at line 65-66 partially explains this but could be clearer. Finding 4: Potential null reference in wildcard configuration query comment
The XML comment states "rows in theIOrganizationIntegrationConfigurationRepository that have null EventType" but should reference the table/entity, not the repository interface. This is a documentation clarity issue. Suggested fix: /// rows in the OrganizationIntegrationConfiguration table that have null EventType are consideredFinding 5: Missing cache invalidation for wildcard configurations
When creating, updating, or deleting a configuration, the code only invalidates the specific event type cache entry. However, if Current code: awaitcache.RemoveAsync(EventIntegrationsCacheConstants.BuildCacheKeyForOrganizationIntegrationConfigurationDetails(organizationId:organizationId,integrationType:integration.Type,eventType:configuration.EventType// Could be null for wildcards)); Suggested enhancement: When Code Quality & Technical DebtFinding 6: Improved error handling and validation
The duplicate integration check now properly returns Finding 7: Cache TTL increased from interval-based to 1 day
The new 1-day TTL is appropriate given the proactive cache invalidation strategy. However, consider documenting this decision in the code or ADR to explain why such a long TTL is safe (i.e., because of backplane-based invalidation). Test Coverage ConcernsFinding 8: Low patch coverage reported by Codecov The PR shows 59.12% patch coverage with 56 lines missing coverage. Key areas lacking coverage:
While the new Good Practices Observed
Action Items
|
| var query = from oic in dbContext.OrganizationIntegrationConfigurations | ||
| join oi in dbContext.OrganizationIntegrations on oic.OrganizationIntegrationId equals oi.Id into oioic | ||
| from oi in dbContext.OrganizationIntegrations |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
❌Critical Issue: Incorrect JOIN logic
This query has redundant and incorrect JOIN syntax:
- Line 20: Creates a LEFT JOIN
into oioicbut never uses the result - Line 21: This
from oi in dbContext.OrganizationIntegrationscreates a CROSS JOIN because it's not filtered by the previous join
This will likely produce incorrect results (Cartesian product) or duplicate records.
Fix: Remove theinto oioic and the redundantfrom clause:
varquery=fromoicindbContext.OrganizationIntegrationConfigurations joinoiindbContext.OrganizationIntegrations onoic.OrganizationIntegrationId equalsoi.Idwhereoi.OrganizationId==_organizationId&&oi.Type==_integrationType&&!oic.EventType.HasValue
This pattern matches the existing query inOrganizationIntegrationConfigurationDetailsReadManyByEventTypeOrganizationIdIntegrationTypeQuery.cs in the same directory.
github-actionsbot commentedNov 26, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Great job! No new security vulnerabilities introduced in this pull request |
codecovbot commentedNov 26, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@## main #6650 +/- ##==========================================+ Coverage 53.27% 57.11% +3.83%========================================== Files 1906 1906 Lines 84973 85025 +52 Branches 7639 7638 -1 ==========================================+ Hits 45268 48558 +3290+ Misses 37952 34638 -3314- Partials 1753 1829 +76 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|

📔 Objective
This PR moves the most high-traffic piece of event integrations over to the new extended cache. This part is the processing that happens every time when receive an event. We need to fetch the integrations from the database and determine if an integration should be fire. Previously, we had a home-grown database that would load all integrations into memory on a fixed interval. This PR replaces that with extended cache.
There are a number of benefits to having this in extended cache:
In addition I've cleaned up the docs and fixed an error that I noticed while testing this (Trying to create an integration of the same type as an existing one would 500 error. It now returns a
BadRequestException- and we have a new test to validate that)Finally, I have added a method / stored procedure / query for fetching wildcard configurations. These are configurations where EventType is
null, which match all events. We were not calling this directly since we were loading all configurations at once into our old cache. But we now need a way of asking for these directly.⏰ Reminders before review
🦮 Reviewer guidelines
:+1:) or similar for great changes:memo:) or ℹ️ (:information_source:) for notes or general info:question:) for questions:thinking:) or 💭 (:thought_balloon:) for more open inquiry that's not quite a confirmed issue and could potentially benefit from discussion:art:) for suggestions / improvements:x:) or:warning:) for more significant problems or concerns needing attention:seedling:) or ♻️ (:recycle:) for future improvements or indications of technical debt:pick:) for minor or nitpick changes