Example #1
0
        private IEnumerable <IAggregateRootEvent> GetAggregateHistoryInternal(Guid aggregateId, bool takeWriteLock)
        {
            _usageGuard.AssertNoContextChangeOccurred(this);
            _schemaManager.SetupSchemaIfDatabaseUnInitialized();
            lock (AggregateLockManager.GetAggregateLockObject(aggregateId))
            {
                var cachedAggregateHistory = _cache.GetCopy(aggregateId);

                var newEventsFromDatabase = _eventReader.GetAggregateHistory(
                    aggregateId: aggregateId,
                    startAfterInsertedVersion: cachedAggregateHistory.MaxSeenInsertedVersion,
                    takeWriteLock: takeWriteLock);

                var containsRefactoringEvents = newEventsFromDatabase.Where(IsRefactoringEvent).Any();
                if (containsRefactoringEvents && cachedAggregateHistory.MaxSeenInsertedVersion > 0)
                {
                    _cache.Remove(aggregateId);
                    return(GetAggregateHistoryInternal(aggregateId: aggregateId, takeWriteLock: takeWriteLock));
                }

                var currentHistory = cachedAggregateHistory.Events.Count == 0
                                                   ? SingleAggregateInstanceEventStreamMutator.MutateCompleteAggregateHistory(_migrationFactories, newEventsFromDatabase)
                                                   : cachedAggregateHistory.Events.Concat(newEventsFromDatabase).ToList();

                //Should within a transaction a process write events, read them, then fail to commit we will have cached events that are not persisted unless we refuse to cache them here.
                if (!_aggregatesWithEventsAddedByThisInstance.Contains(aggregateId))
                {
                    var maxSeenInsertedVersion = newEventsFromDatabase.Any()
                                                     ? newEventsFromDatabase.Max(@event => @event.InsertedVersion)
                                                     : cachedAggregateHistory.MaxSeenInsertedVersion;

                    _cache.Store(
                        aggregateId,
                        new SqlServerEventStoreEventsCache.Entry(events: currentHistory, maxSeenInsertedVersion: maxSeenInsertedVersion));
                }

                return(currentHistory);
            }
        }
Example #2
0
        public void PersistMigrations()
        {
            this.Log().Warn($"Starting to persist migrations");

            long migratedAggregates = 0;
            long updatedAggregates  = 0;
            long newEventCount      = 0;
            var  logInterval        = 1.Minutes();
            var  lastLogTime        = DateTime.Now;

            const int recoverableErrorRetriesToMake = 5;

            var aggregateIdsInCreationOrder = StreamAggregateIdsInCreationOrder().ToList();

            foreach (var aggregateId in aggregateIdsInCreationOrder)
            {
                try
                {
                    var succeeded = false;
                    int retries   = 0;
                    while (!succeeded)
                    {
                        try
                        {
                            //todo: Look at batching the inserting of events in a way that let's us avoid taking a lock for a long time as we do now. This might be a problem in production.
                            using (var transaction = new TransactionScope(TransactionScopeOption.Required, scopeTimeout: 10.Minutes()))
                            {
                                lock (AggregateLockManager.GetAggregateLockObject(aggregateId))
                                {
                                    var updatedThisAggregate = false;
                                    var original             = _eventReader.GetAggregateHistory(aggregateId: aggregateId, takeWriteLock: true).ToList();

                                    var startInsertingWithVersion = original.Max(@event => @event.InsertedVersion) + 1;

                                    var updatedAggregatesBeforeMigrationOfThisAggregate = updatedAggregates;

                                    SingleAggregateInstanceEventStreamMutator.MutateCompleteAggregateHistory(
                                        _migrationFactories,
                                        original,
                                        newEvents =>
                                    {
                                        //Make sure we don't try to insert into an occupied InsertedVersion
                                        newEvents.ForEach(@event => @event.InsertedVersion = startInsertingWithVersion++);
                                        //Save all new events so they get an InsertionOrder for the next refactoring to work with in case it acts relative to any of these events
                                        _eventWriter.InsertRefactoringEvents(newEvents);
                                        updatedAggregates    = updatedAggregatesBeforeMigrationOfThisAggregate + 1;
                                        newEventCount       += newEvents.Count();
                                        updatedThisAggregate = true;
                                    });

                                    if (updatedThisAggregate)
                                    {
                                        _eventWriter.FixManualVersions(aggregateId);
                                    }

                                    transaction.Complete();
                                    _cache.Remove(aggregateId);
                                }
                                migratedAggregates++;
                                succeeded = true;
                            }
                        }
                        catch (Exception e) when(IsRecoverableSqlException(e) && ++retries <= recoverableErrorRetriesToMake)
                        {
                            this.Log().Warn($"Failed to persist migrations for aggregate: {aggregateId}. Exception appers to be recoverable so running retry {retries} out of {recoverableErrorRetriesToMake}", e);
                        }
                    }
                }
                catch (Exception exception)
                {
                    this.Log().Error($"Failed to persist migrations for aggregate: {aggregateId}", exception: exception);
                }

                if (logInterval < DateTime.Now - lastLogTime)
                {
                    lastLogTime = DateTime.Now;
                    Func <int> percentDone = () => (int)(((double)migratedAggregates / aggregateIdsInCreationOrder.Count) * 100);
                    this.Log().Info($"{percentDone()}% done. Inspected: {migratedAggregates} / {aggregateIdsInCreationOrder.Count}, Updated: {updatedAggregates}, New Events: {newEventCount}");
                }
            }

            this.Log().Warn($"Done persisting migrations.");
            this.Log().Info($"Inspected: {migratedAggregates} , Updated: {updatedAggregates}, New Events: {newEventCount}");
        }