public async Task UpdateAtomicAsync(Func <Task <TDocument> > updateAsync, Func <TDocument, Task> afterUpdateAsync = null) { if (_isDistributed) { try { _ = await _distributedCache.GetStringAsync(_options.CacheIdKey); } catch { await DocumentStore.CancelAsync(); throw new InvalidOperationException($"Can't update the '{typeof(TDocument).Name}' if not able to access the distributed cache"); } } var delegates = ShellScope.GetOrCreateFeature <UpdateDelegates>(); if (delegates.UpdateDelegateAsync == null || !delegates.UpdateDelegateAsync.GetInvocationList().Contains(updateAsync)) { delegates.UpdateDelegateAsync += () => updateAsync(); } if (afterUpdateAsync != null && (delegates.AfterUpdateDelegateAsync == null || !delegates.AfterUpdateDelegateAsync.GetInvocationList().Contains(afterUpdateAsync))) { delegates.AfterUpdateDelegateAsync += document => afterUpdateAsync(document); } DocumentStore.AfterCommitSuccess <TDocument>(async() => { (var locker, var locked) = await _distributedLock.TryAcquireLockAsync( _options.CacheKey + "_LOCK", TimeSpan.FromMilliseconds(_options.LockTimeout), TimeSpan.FromMilliseconds(_options.LockExpiration)); if (!locked) { return; } await using var acquiredLock = locker; TDocument document = null; foreach (var d in delegates.UpdateDelegateAsync.GetInvocationList()) { document = await((UpdateDelegate)d)(); } document.Identifier ??= IdGenerator.GenerateId(); await SetInternalAsync(document); if (delegates.AfterUpdateDelegateAsync != null) { foreach (var d in delegates.AfterUpdateDelegateAsync.GetInvocationList()) { await((AfterUpdateDelegate)d)(document); } } }); }