-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Add CQRS and caching support for OrganizationIntegrations #6689
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add CQRS and caching support for OrganizationIntegrations #6689
Conversation
|
Claude finished @brant-livefront's task —— View job Code Review Complete ✅SummaryI've completed a comprehensive review of PR #6689. Overall Assessment: APPROVE This PR successfully implements the CQRS pattern for OrganizationIntegrations with proper cache invalidation on the write side. The code quality is high, test coverage is comprehensive, and the implementation follows Bitwarden's coding standards. Key Findings✅ Strengths:
❓ Questions for Clarification: Race condition in CreateAsync duplicate checkIn var existingIntegrations = await integrationRepository
.GetManyByOrganizationAsync(integration.OrganizationId);
if (existingIntegrations.Any(i => i.Type == integration.Type))
{
throw new BadRequestException("An integration of this type already exists for this organization.");
}If two create requests for the same integration type arrive simultaneously, both could pass the duplicate check before either writes to the database. Is this protected by:
Cache invalidation transaction semanticsAll three commands call await integrationRepository.ReplaceAsync(updatedIntegration);
await cache.RemoveByTagAsync(
EventIntegrationsCacheConstants.BuildCacheTagForOrganizationIntegration(
organizationId: organizationId,
integrationType: integration.Type
));Does 🎨 Suggested Improvements (Optional): 1. Consider extracting duplicate validation logicThe duplicate type check in 2. Add integration tests for distributed cache invalidationWhile unit tests verify cache invalidation is called, integration tests would verify that:
Current test coverage is adequate for merge, but consider adding these in a follow-up for production confidence. 3. Consider adding cache metrics/loggingAdding debug-level logging for cache invalidation operations would aid production observability: logger.LogDebug(
"Invalidating cache for organization {OrganizationId} integration type {IntegrationType}",
organizationId,
integration.Type);Would help with debugging cache issues and understanding invalidation patterns. Security & Compliance✅ Authorization: All controller endpoints properly check Technical Implementation✅ CQRS Pattern: Commands and Queries properly separated with no side effects in queries
✅ Test Coverage: Excellent coverage across all scenarios (happy paths, error cases, cache verification) Files Reviewed (18 files)Controllers: OrganizationIntegrationController.cs - Refactored to use CQRS Verdict👍 Approve - This is solid work that correctly implements the write-side cache invalidation using the CQRS pattern. The two questions raised are for clarification only and don't block merge. All critical requirements are met, and the code follows Bitwarden standards. |
|
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #6689 +/- ##
==========================================
- Coverage 57.42% 53.64% -3.79%
==========================================
Files 1921 1926 +5
Lines 85650 85720 +70
Branches 7687 7687
==========================================
- Hits 49187 45981 -3206
- Misses 34618 37967 +3349
+ Partials 1845 1772 -73 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
… EventIntegrationsServiceCollectionExtensions handles this instead)
…gurations for an event (including wildcards)
… into brant/add-cqrs-and-cache-support-for-organization-integrations
… into brant/add-cqrs-and-cache-support-for-organization-integrations
|
The base branch was changed.





📔 Objective
This PR extends the work in PR #6650 where we added caching to the event integration configurations. The PR handled the read side of the cache, this PR (and an additional followup) will handle the write side of the PR. That is, when an integration is changed in the DB, we need to flush the cache so that any stale records are removed. This PR focuses on just the
OrganizationIntegrationpiece and an additional PR will be added forOrganizationIntegrationConfigurations.The DI piece is a bit tricky for these. Since they are dependent on the named extended cache, they can't be instantiated with the rest of the OrganizationFeatures pieces. Instead, this PR creates
EventIntegrationsServiceCollectionExtensions(and associated tests) to create a clean way for Startup in API to get them into the service collection cleanly. This extension will be a landing place for more of the custom event integration methods in ServiceCollectionExtensions in future PRs. It will be a big help to have those separated out and testable.Finally, there's a few cleanup things that I noticed in doing this work. We were allowing someone to change the integration type when updating an integration (which would also have cache implications). Instead, I've changed it to deny an update that changes the IntegrationType (that should be a brand new integration instead).
This PR represents a replacement for #6675 which will be closed. I'm splitting those changes up into more digestible PRs.
⏰ 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