Fix warmup regression: avoid per-expression AppDomain assembly scan (fixes #739)#740
Merged
YogeshPraj merged 1 commit intoJun 11, 2026
Merged
Conversation
Since 71d59dc, CustomTypeProvider.GetCustomTypes() includes base.GetCustomTypes(), which scans every assembly in the AppDomain for [DynamicLinqType] types. DefaultDynamicLinqCustomTypeProvider only caches that scan per provider instance, and RuleExpressionParser.Parse built a new ParsingConfig + CustomTypeProvider for every expression parsed, so the scan ran for every expression in every rule (KeywordsHelper enumerates the full type set on each ExpressionParser construction). For workflows with thousands of rules this regressed warmup ~6.6x versus 5.0.3 (113.8s vs 17.3s for 20,000 rules with local params and 174 loaded assemblies). The compiled-delegate cache from microsoft#727 does not help here because each rule expression is unique. Fix: - Reuse one ParsingConfig/CustomTypeProvider across parses, rebuilding only when ReSettings.CustomTypes is swapped (AutoRegisterInputType replaces the array on workflow registration). - Memoize the merged custom-type set in CustomTypeProvider; it is fixed after construction but was rebuilt (including the assembly scan) on every GetCustomTypes() call. With this change the same 20,000-rule benchmark warms up in 16.3s, matching 5.0.3, with identical rule results. Addresses the remaining root cause behind microsoft#707. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
Author
@microsoft-github-policy-service agree |
YogeshPraj
approved these changes
Jun 11, 2026
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.
Problem
Since 71d59dc (#675),
CustomTypeProvider.GetCustomTypes()includesbase.GetCustomTypes(), which scans every AppDomain assembly for[DynamicLinqType]types. System.Linq.Dynamic.Core caches that scan only per provider instance, andRuleExpressionParser.Parsebuilds a newParsingConfig+CustomTypeProviderfor every expression parsed (Dynamic LINQ'sKeywordsHelperenumerates the full type set on eachExpressionParserconstruction). The result is one full assembly scan per expression, per rule.For large workflows this regressed warmup ~6.6x vs 5.0.3 (113.8 s vs 17.3 s for 20,000 rules with local params and 174 loaded assemblies). The compiled-delegate cache from #727 does not help because each rule expression is unique. This is the remaining root cause behind #707.
Change
RuleExpressionParser: reuse oneParsingConfig/CustomTypeProvideracross parses; rebuild only whenReSettings.CustomTypesis swapped (AutoRegisterInputTypereplaces the array on workflow registration), preserving the behavior introduced by [Bug Fix] Handling of Automatic Type Registration #675.CustomTypeProvider: memoize the merged custom-type set; it is fixed after construction but was rebuilt — including the assembly scan — on everyGetCustomTypes()call.Results
Same 20,000-rule benchmark: 113.8 s → 16.3 s, matching 5.0.3, with identical rule results.
All 170 existing unit tests pass. No public API change.