Sitecore.Commerce.Core.GetEnvironmentCacheBlockが並列スレッドで実行されると、Commerce Engineインスタンス(Authoring、Shopsなど)のログ ファイルに以下の例外が表示される場合があります。
System.InvalidOperationException: Collection was modified; enumeration operation may not execute
この問題の原因は、IEnumeratorを使用してコレクションを反復処理している間、コレクションを変更できないことに関連しています。このような変更により、前述の例外がスローされ、以下のスタック トレースが発生します。
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()
この問題を解決するには、解決策として以下のオプションを検討してください。
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(); } } .......................... } }