Add opt-in parallel rule compilation (improved on top of #741)#744
Merged
YogeshPraj merged 2 commits intoJun 11, 2026
Merged
Conversation
Rule compilation during workflow registration was strictly serial. For workflows with very large rule counts (10k+), warmup is dominated by this loop even after expression parsing is fixed. Adds ReSettings.EnableParallelRuleCompilation (default false). When enabled, rules are compiled with Parallel.For and results are added to the compiled-rule dictionary in the original order. An AggregateException from the parallel loop is unwrapped so the first failing rule surfaces its original exception, preserving the serial error contract (verified by the existing ExecuteRule_MissingMethodInExpression_ReturnsRulesFailed test). Benchmark, 20,000 unique rules with local params: 16.2s serial -> 4.7s parallel on a 16-thread machine. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Builds on microsoft#741 by @benluersen. The original opt-in parallel rule compilation is sound but had two latent footguns and no test coverage for the parallel path: 1. UseFastExpressionCompiler interaction (~2.7× regression when both flags are on, per the PR description) — users would flip the flag and silently get slower. The engine now declines to parallelize when UseFastExpressionCompiler = true and falls back to serial. 2. Below ~32 rules, Parallel.For's scheduling overhead exceeds the speedup. Added a MinRulesForParallelCompilation threshold so small workflows aren't penalised by enabling the flag globally. 3. catch (AggregateException ae) accessed ae.InnerExceptions[0] without bounds-checking. Replaced with a `when` filter so the catch only matches when there's actually an inner exception to rethrow. XML doc on ReSettings.EnableParallelRuleCompilation now spells out both fallback conditions so the contract is obvious without reading the implementation. New ParallelRuleCompilationTest covers: - Parallel and serial produce identical RuleResultTree shape and outcomes - The first compile failure surfaces as a per-rule ExceptionMessage, not an AggregateException - UseFastExpressionCompiler + parallel still produces correct results (the fallback is silent, only observable in benchmarks) - Sub-threshold workflows execute correctly with the flag enabled All 174 unit tests pass on net6 / net8 / net9 / net10. Co-authored-by: Ben Luersen <ben.luersen@gmail.com>
benluersen
approved these changes
Jun 11, 2026
benluersen
left a comment
Contributor
There was a problem hiding this comment.
This looks good to me
sagarambilpure
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.
Summary
Picks up @benluersen's work from #741 and adds the three improvements I flagged in that PR's review, packaged for the upcoming release.
Ben's original commit (
d8087f1) is preserved in the history; my changes layer on top as a separate commit so attribution stays clean. If @benluersen would rather take these changes back into #741 directly and have this one close, I'm happy with that outcome too — the goal is just to unblock the release. Otherwise this PR can land as-is.What's preserved from #741
ReSettings.EnableParallelRuleCompilation(defaultfalse).Parallel.Forrule compilation when the flag is enabled.AggregateExceptionunwrap so callers see the underlying compile error.Original perf claim from #741: 20,000-rule workflow, 16.2s serial → 4.7s parallel (~3.4×).
What this PR adds on top
1. Guard against
UseFastExpressionCompiler(the silent footgun)The #741 description noted a 2.7× regression (12.9s vs 4.7s) when both
EnableParallelRuleCompilationandUseFastExpressionCompilerare set. Users would enable the flag for a warmup win and silently get slower. The engine now declines to parallelize that combination and falls back to serial: