Fix race condition in ActivationCollector.DeactivateInDueTimeOrder#9704
Closed
Fix race condition in ActivationCollector.DeactivateInDueTimeOrder#9704
Conversation
…s before OrderBy Co-authored-by: ReubenBond <203839+ReubenBond@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] ActivationCollector.DeactivateInDueTimeOrder throws exception
Fix race condition in ActivationCollector.DeactivateInDueTimeOrder
Oct 2, 2025
ReubenBond
approved these changes
Oct 23, 2025
Member
|
I would close it in favor of #9740, which has a more consistent test reproducing the issue. |
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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
The
DeactivateInDueTimeOrdermethod throws anArgumentExceptionwhen multiple threads concurrently modify the activation buckets during enumeration:Root Cause
The method was calling
buckets.OrderBy(b => b.Key)directly on aConcurrentDictionary<DateTime, Bucket>. When LINQ'sOrderByinternally materializes the collection to an array for sorting, concurrent modifications to the dictionary cause the array size calculation to become invalid, resulting in the exception.While
ConcurrentDictionaryis thread-safe for individual operations, LINQ operations that materialize collections are not safe during concurrent modifications.Solution
Changed line 365 in
src/Orleans.Runtime/Catalog/ActivationCollector.cs:This creates a point-in-time snapshot of the dictionary before sorting, eliminating the race condition. This pattern is already used elsewhere in the same class (in the
ToString()method at line 219), making the codebase consistent.Testing
Added
DeactivateInDueTimeOrder_HandlesRaceDuringEnumerationtest that:This test would fail with the original code due to the race condition.
Impact
.ToList())Fixes #9702
Warning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
0t3vsblobprodcus362.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)dotnet build src/Orleans.Runtime/Orleans.Runtime.csproj --configuration Debug(dns block)1k9vsblobprodcus379.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)1s1vsblobprodcus386.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)37bvsblobprodcus311.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)4m6vsblobprodcus384.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)dotnet build src/Orleans.Runtime/Orleans.Runtime.csproj --configuration Debug(dns block)4zjvsblobprodcus390.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)96bvsblobprodcus338.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)dotnet build src/Orleans.Runtime/Orleans.Runtime.csproj --configuration Debug(dns block)cflvsblobprodcus383.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)dotnet build src/Orleans.Runtime/Orleans.Runtime.csproj --configuration Debug(dns block)ckzvsblobprodcus347.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)dotnet build src/Orleans.Runtime/Orleans.Runtime.csproj --configuration Debug(dns block)d0svsblobprodcus381.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)dnceng.pkgs.visualstudio.comdotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)dotnet build src/Orleans.Runtime/Orleans.Runtime.csproj --configuration Debug(dns block)fdpvsblobprodcus345.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)frdvsblobprodcus327.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)dotnet build src/Orleans.Runtime/Orleans.Runtime.csproj --configuration Debug(dns block)imzvsblobprodcus368.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)dotnet build src/Orleans.Runtime/Orleans.Runtime.csproj --configuration Debug(dns block)jd4vsblobprodcus366.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)dotnet build src/Orleans.Runtime/Orleans.Runtime.csproj --configuration Debug(dns block)josvsblobprodcus372.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)jrqvsblobprodcus343.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)dotnet build src/Orleans.Runtime/Orleans.Runtime.csproj --configuration Debug(dns block)k0ivsblobprodcus356.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)dotnet build src/Orleans.Runtime/Orleans.Runtime.csproj --configuration Debug(dns block)kh4vsblobprodcus325.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)dotnet build src/Orleans.Runtime/Orleans.Runtime.csproj --configuration Debug(dns block)ljcvsblobprodcus317.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)lylvsblobprodcus31.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)dotnet build src/Orleans.Runtime/Orleans.Runtime.csproj --configuration Debug(dns block)m6xvsblobprodcus342.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)dotnet build src/Orleans.Runtime/Orleans.Runtime.csproj --configuration Debug(dns block)mfjvsblobprodcus373.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)p2ovsblobprodcus312.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)pc2vsblobprodcus360.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)dotnet build src/Orleans.Runtime/Orleans.Runtime.csproj --configuration Debug(dns block)pdfvsblobprodcus380.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)dotnet build src/Orleans.Runtime/Orleans.Runtime.csproj --configuration Debug(dns block)rcxvsblobprodcus328.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)dotnet build src/Orleans.Runtime/Orleans.Runtime.csproj --configuration Debug(dns block)se1vsblobprodcus349.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)dotnet build src/Orleans.Runtime/Orleans.Runtime.csproj --configuration Debug(dns block)sqdvsblobprodcus333.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)st8vsblobprodcus339.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)u3hvsblobprodcus371.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)x3yvsblobprodcus370.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)xupvsblobprodcus332.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)yluvsblobprodcus367.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)dotnet build src/Orleans.Runtime/Orleans.Runtime.csproj --configuration Debug(dns block)yttvsblobprodcus357.vsblob.vsassets.iodotnet build test/NonSilo.Tests/NonSilo.Tests.csproj --configuration Debug(dns block)dotnet build src/Orleans.Runtime/Orleans.Runtime.csproj --configuration Debug(dns block)If you need me to access, download, or install something from one of these locations, you can either:
Original prompt
💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.
Microsoft Reviewers: Open in CodeFlow