Minimal API负载测试中偶现OptionsMonitor.Dispose()时的集合修改异常
Minimal API负载测试中偶现OptionsMonitor.Dispose()时的集合修改异常
兄弟,我太懂这种偶现bug的痛苦了!3万请求里才出10次,排查起来真的头大。先给你拆解下这个问题:
你碰到的这个System.InvalidOperationException,根源是OptionsMonitor内部维护的监听者集合在高并发下被并发修改了——负载测试700RPS的场景下,Dispose操作在枚举集合清理监听者的同时,刚好有其他线程在修改这个集合(比如动态更新配置、添加新的Options监听),这就触发了.NET里“集合被修改时不能枚举”的安全检查。
先把你贴的错误日志整理下,方便更清晰地定位:
System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
at System.Collections.Generic.List1.Enumerator.MoveNext() at Microsoft.Extensions.Options.OptionsMonitor1.Dispose()
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.DisposeAsync()
接下来给你几个实打实的排查和解决方向:
- 给动态修改Options的逻辑加锁:如果你的代码里有动态更新配置、手动添加/移除Options监听的操作,赶紧给这些逻辑加个线程安全的锁(比如
lock或者SemaphoreSlim),确保在Dispose枚举集合的时候,没有其他线程在修改它。 - 核对服务生命周期配置:Minimal API里很容易在服务注册时踩坑——比如把本该是Scoped的Options相关服务注册成了Singleton,或者反过来。高并发下Scope的释放和OptionsMonitor的Dispose时机冲突,也会触发这个问题。去检查下
Program.cs里的服务注册代码,特别是AddOptions相关的配置。 - 升级Options相关依赖包:官方在后续的.NET补丁版本里,针对OptionsMonitor的并发场景做过修复。你可以把
Microsoft.Extensions.Options以及相关的依赖包升级到对应.NET版本的最新稳定版,说不定直接就解决了这个偶现bug。 - 自定义线程安全的OptionsMonitor:如果上面的方法都没用,你可以自己封装一个OptionsMonitor,用
ReaderWriterLockSlim来保护内部集合的枚举和修改操作——枚举的时候加读锁,修改的时候加写锁,从根源上避免并发冲突。
对了,如果你有自定义的Options实现代码,也仔细检查下有没有在多线程下修改集合的逻辑,很多时候问题就藏在这些容易忽略的细节里。
内容来源于stack exchange
相关产品推荐
相关产品推荐

