public async Task ExecuteInstanceWithQueuedSnapshot()
        {
            var ssMock = new Mock <ISnapshotStore>(MockBehavior.Strict);

            ssMock.Setup(s => s.SaveSnapshots(It.IsAny <IList <DomainObjectSnapshot> >()))
            .ReturnsAsync(Result.Success)
            .Verifiable("SaveSnapshots was never called");

            var provider = new ServiceCollection()
                           .AddLogging()
                           .AddSingleton <IncrementalSnapshotService>()
                           .AddSingleton(ssMock.Object)
                           .BuildServiceProvider();

            var instance = provider.GetRequiredService <IncrementalSnapshotService>();

            using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(60));
            await instance.StartAsync(cts.Token);

            IncrementalSnapshotService.QueueSnapshot(new DomainObjectSnapshot("Test-Snapshot", "Snapshot1", "{}", 4711, 4711));

            await Task.Delay(TimeSpan.FromSeconds(4), cts.Token);

            await instance.StopAsync(cts.Token);

            ssMock.Verify();
        }
        private async Task <IResult <T> > ReplayObjectInternal <T>(T domainObject,
                                                                   string identifier,
                                                                   long maxVersion,
                                                                   string cacheKey)
            where T : DomainObject
        {
            try
            {
                if (TryGetCachedItem(cacheKey, maxVersion, out T cachedInstance))
                {
                    domainObject = cachedInstance;
                }
                else
                {
                    await ApplyLatestSnapshot(domainObject, identifier, maxVersion, cacheKey);
                }

                _logger.LogDebug($"replaying events for '{identifier}', '{domainObject.MetaVersion}' => '{maxVersion}'");

                // if the target-object is in any way streamed we save a snapshot of it
                if ((await StreamObjectToVersion(domainObject, maxVersion, identifier)).Any())
                {
                    IncrementalSnapshotService.QueueSnapshot(domainObject.CreateSnapshot());
                }

                var size          = domainObject.CalculateCacheSize();
                var priority      = domainObject.GetCacheItemPriority();
                var cacheDuration = GetCacheTime();

                _logger.LogInformation($"item cached: duration={cacheDuration:g}; priority={priority}; size={size}; key={cacheKey}");

                var cts = new CancellationTokenSource(cacheDuration);
                (CancellationTokenSource, ILogger <DomainObjectStore>)callbackParams = (cts, _logger);

                _memoryCache.Set(cacheKey,
                                 domainObject,
                                 new MemoryCacheEntryOptions()
                                 .SetPriority(priority)
                                 .SetSize(size)
                                 .AddExpirationToken(new CancellationChangeToken(cts.Token))
                                 .RegisterPostEvictionCallback((key, value, reason, state) =>
                {
                    var(tokenSource, logger) = ((CancellationTokenSource, ILogger <DomainObjectStore>))state;
                    tokenSource?.Dispose();
                    logger?.LogInformation($"cached item '{key}' evicted: {reason}");
                }, callbackParams));

                return(Result.Success(domainObject));
            }
            catch (Exception e)
            {
                _logger.LogWarning(e, $"failed to retrieve {typeof(T).Name} from EventStore (" +
                                   $"{nameof(identifier)}: {identifier}, " +
                                   $"{nameof(maxVersion)}: {maxVersion}, " +
                                   $"{nameof(cacheKey)}: {cacheKey})");
                return(Result.Error <T>($"failed to retrieve {typeof(T).Name} from EventStore", ErrorCode.FailedToRetrieveItem));
            }
        }
Esempio n. 3
0
        /// <summary>
        ///     write the recorded events to the given <see cref="IEventStore" />
        /// </summary>
        /// <param name="store"></param>
        /// <returns></returns>
        public virtual async Task <IResult> WriteRecordedEvents(IEventStore store)
        {
            try
            {
                // if we don't have anything to store, we return immediately
                if (!CapturedDomainEvents.Any())
                {
                    return(Result.Success());
                }

                // take lock and see if another instance may already drain this queue
                lock (_eventLock)
                {
                    if (_eventsBeingDrained)
                    {
                        return(Result.Success());
                    }

                    _eventsBeingDrained = true;
                }

                MetaVersion = CurrentVersion = await store.WriteEvents(CapturedDomainEvents);

                CapturedDomainEvents.Clear();
                IncrementalSnapshotService.QueueSnapshot(CreateSnapshot());

                return(Result.Success());
            }
            catch (Exception e)
            {
                return(Result.Error($"could not write events to IEventStore: {e.Message}", ErrorCode.Undefined));
            }
            finally
            {
                lock (_eventLock)
                {
                    _eventsBeingDrained = false;
                }
            }
        }
 public void QueueNullSnapshot()
 {
     IncrementalSnapshotService.QueueSnapshot(null);
 }
 public void QueueSnapshot()
 {
     IncrementalSnapshotService.QueueSnapshot(new DomainObjectSnapshot("Test-Snapshot", "Snapshot1", "{}", 4711, 4711));
 }