The following exception might appear in the log files of a Commerce Engine instance (Authoring, Shops, and so on) when Sitecore.Commerce.Core.GetEnvironmentCacheBlock is executed in parallel threads:
System.InvalidOperationException: Collection was modified; enumeration operation may not execute
The cause of the issue is related to the fact that a collection cannot be modified while IEnumerator is used to iterate it. Such modification leads to throwing the previously mentioned exception with the following stack trace:
ERROR Pipeline completed with error System.Exception: Error processing block: Core.block.GetEnvironmentCache ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.InvalidOperationException: Collection was modified; enumeration operation may not execute. at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource) at System.Collections.Generic.List`1.Enumerator.MoveNextRare() at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source, Func`2 predicate) at Sitecore.Commerce.Core.GetEnvironmentCacheBlock.Run(EnvironmentCacheArgument arg, CommercePipelineExecutionContext context) --- End of inner exception stack trace --- at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor) at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) at Sitecore.Framework.Pipelines.ReflectionPipelineBlockRunner.<InvokeBlock>d__2.MoveNext() --- End of inner exception stack trace --- at Sitecore.Framework.Pipelines.ReflectionPipelineBlockRunner.<InvokeBlock>d__2.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Sitecore.Framework.Pipelines.BasePipelineBlockRunner.<Run>d__3`1.MoveNext()
To resolve the issue, consider the following options for the solution:
public class GetEnvironmentCacheBlock : PipelineBlock<EnvironmentCacheArgument, ICache, CommercePipelineExecutionContext> { .................. private static readonly ReaderWriterLockSlim objectsLock = new ReaderWriterLockSlim(); ....................... public override Task<ICache> Run(EnvironmentCacheArgument arg, CommercePipelineExecutionContext context) { ........................... var environmentCacheComponent = this._nodeContext.GetObjects<EnvironmentCacheComponent>().FirstOrDefault(p => p.Name.Equals(environmentName, StringComparison.OrdinalIgnoreCase)); if (environmentCacheComponent != null) { try { objectsLock.EnterReadLock(); var existingCache = environmentCacheComponent.Caches.FirstOrDefault(p => p.Name.Equals(cacheName, StringComparison.OrdinalIgnoreCase)); if (existingCache != null) { return Task.FromResult(existingCache); } } finally { objectsLock.ExitReadLock(); } try { objectsLock.EnterWriteLock(); context.Logger.LogInformation($"MemCache.CreateCache.{cacheName}"); var environmentCache = environmentCacheComponent.CacheFactory(environmentCacheComponent.CacheStore, cacheName); environmentCacheComponent.Caches.Add(environmentCache); return Task.FromResult(environmentCache); } finally { objectsLock.ExitWriteLock(); } } .......................... } }