Improve batch state checker performance and add RequireFeaturesSimpleBatchStateChecker#25276
Open
Improve batch state checker performance and add RequireFeaturesSimpleBatchStateChecker#25276
Conversation
When IsEnabledAsync(TState[]) evaluates non-batch checkers, the original implementation called InternalIsEnabledAsync for each state, which created a new DI scope every time. In real-world scenarios with thousands of permissions (e.g. 4050 permissions each with RequireFeaturesSimpleStateChecker), this caused N scope creations and N redundant Redis queries, resulting in ~3.5s latency. This change shares a single DI scope across all non-batch checker evaluations in the batch path by extracting EvaluateCheckersAsync and calling it directly with the shared scope. Each state still gets an isolated ITransientCachedServiceProvider to prevent transient service leakage across states, while scoped services (e.g. IFeatureChecker) are naturally shared within the scope, enabling cache reuse. The single-state path (IsEnabledAsync(TState)) remains completely unchanged.
Contributor
There was a problem hiding this comment.
Pull request overview
Improves SimpleStateCheckerManager<TState>.IsEnabledAsync(TState[]) performance by avoiding per-state DI scope creation when evaluating non-batch checkers, while adding regression tests to validate correctness and scope/cached-provider isolation behavior.
Changes:
- Reuses the existing batch scope when evaluating non-batch checkers by extracting
EvaluateCheckersAsync. - Uses
ITransientCachedServiceProviderper state in the batch/non-batch path to isolate transient caching across states. - Adds new tests covering correctness, skip behavior, and scope isolation (including nested single-state calls).
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerManager.cs | Refactors evaluation logic to reuse one scope in the batch path and introduces EvaluateCheckersAsync. |
| framework/test/Volo.Abp.Core.Tests/Volo/Abp/SimpleStateChecking/SimpleStateChecker_ScopeIsolation_Tests.cs | Adds probe-based tests validating shared batch scope + per-state cached provider isolation and nested-call scope behavior. |
| framework/test/Volo.Abp.Core.Tests/Volo/Abp/SimpleStateChecking/SimpleStateChecker_BatchSingleScope_Tests.cs | Adds functional tests ensuring batch evaluation of non-batch checkers remains correct after scope reuse. |
SimpleStateCheckerManager batch performance by sharing a single DI scopeReplace linear scans with Dictionary/HashSet lookups in both RequirePermissionsSimpleBatchStateChecker and RequireFeaturesSimpleBatchStateChecker for consistency.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## rel-10.3 #25276 +/- ##
============================================
- Coverage 50.71% 50.70% -0.02%
============================================
Files 3472 3477 +5
Lines 117140 117489 +349
Branches 8840 8866 +26
============================================
+ Hits 59407 59568 +161
- Misses 55925 56110 +185
- Partials 1808 1811 +3 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
When
IsEnabledAsync(TState[])evaluates non-batch checkers, the original implementation calledInternalIsEnabledAsyncfor each state, creating a new DI scope every time. With thousands of permissions (e.g. 4050 permissions each withRequireFeaturesSimpleStateChecker), this caused N scope creations and N redundant Redis/service queries (~3.5s).SimpleStateCheckerManager changes:
AsyncLocal, creates a newCachedServiceProviderper state to prevent transient service leakage across states.InternalIsEnabledAsyncare fully respected in both paths.RequireFeaturesSimpleBatchStateChecker (new):
Follows the same pattern as
RequirePermissionsSimpleBatchStateChecker:RequireFeatures()extension defaults tobatchCheck: truebatchCheck: falseparameterMenuManagerandToolbarManageruseUse(new ...)to reset per requestIFeatureChecker:
IsEnabledAsync(string[] names)batch method toIFeatureCheckerFeatureCheckerBaseMeasured improvement: 3519ms → 41ms for 4050 permissions with feature state checkers.