Exemplo n.º 1
0
        private async Task <List <IEventMessageDraft> > CreateEventMessagesAsync(IEventSourcedAggregateRoot aggregate, IReadOnlyCollection <DomainAggregateEvent> events)
        {
            var  messages         = new List <IEventMessageDraft>();
            Guid?aggregateClassId = entityTypeManager.TryGetClassInfoByClrType(aggregate.GetType())?.Id;

            if (aggregateClassId == null)
            {
                throw new InvalidOperationException($"Cannot save event sourced aggregate of type {aggregate.GetType()}: its class ID has not been defined");
            }

            foreach (DomainAggregateEvent ev in events)
            {
                IEventMessageDraft message = await eventMessageFactory.CreateMessageAsync(ev);

                message.SetMetadata(BasicEventMetadataNames.AggregateClassId, aggregateClassId.Value.ToString());
                message.SetMetadata(BasicEventMetadataNames.AggregateVersion, (aggregate.Version + 1).ToString());

                if (aggregate is ITenantOwned tenantOwned)
                {
                    message.SetMetadata(BasicEventMetadataNames.AggregateTenantId, tenantOwned.TenantId?.ToString());
                }

                messages.Add(message);
            }

            return(messages);
        }
        public void Set(IEventSourcedAggregateRoot aggregateRoot)
        {
            if (aggregateRoot == null)
            {
                return;
            }

            var aggregateRootId   = aggregateRoot.Id;
            var aggregateRootType = aggregateRoot.GetType();
            var cacheKey          = GetCacheKey(aggregateRootId, aggregateRootType);

            if (_logger.IsEnabled(LogLevel.Debug))
            {
                _logger.LogDebug($"Setting aggregate root to memory cache[LRU], Id: {aggregateRootId}, Type: {aggregateRootType}.");
            }

            _cache.Add(cacheKey, aggregateRoot);
        }
        public async Task CheckpointAsync(
            IEventSourcedAggregateRoot aggregateRoot,
            CancellationToken token = default)
        {
            var aggregateRootId     = aggregateRoot.Id;
            var aggregateRootType   = aggregateRoot.GetType().FullName;
            var aggregateGeneration = aggregateRoot.Generation;
            var aggregateVersion    = aggregateRoot.Version;

            var metrics = await _eventStateBackend.StatMetricsAsync(aggregateRootId, aggregateGeneration, token);

            if (metrics.TriggerCheckpoint(_options))
            {
                var nextGeneration = ++aggregateRoot.Generation;
                var checkpoint     = new AggregateRootCheckpoint <IEventSourcedAggregateRoot>(aggregateRoot.Id, aggregateRoot.GetType(), nextGeneration, aggregateRoot.Version, aggregateRoot);

                var message = $"id: {aggregateRootId}, Type: {aggregateRootType}, Generation: {nextGeneration}, Version: {aggregateVersion}, UnCheckpointedBytes: {metrics.UnCheckpointedBytes} >= {_options.UnCheckpointedBytes}, UnCheckpointedCount: {metrics.UnCheckpointedCount} >= {_options.UnCheckpointedCount}";

                try
                {
                    await _checkpointStateBackend.AppendAsync(checkpoint, token);
                }
                catch (Exception e)
                {
                    _logger.LogInformation($"Checkpointing the aggregate root, {message} has a unknown exception: {LogFormatter.PrintException(e)}.");

                    return;
                }

                _logger.LogInformation($"Checkpointed the aggregate root, {message}.");
            }
            else
            {
                _logger.LogInformation($"No triggering checkpoint for the aggregate root, id: {aggregateRootId}, Type: {aggregateRootType}, Generation: {aggregateGeneration}, Version: {aggregateVersion}, UnCheckpointedBytes: {metrics.UnCheckpointedBytes} < {_options.UnCheckpointedBytes}, UnCheckpointedCount: {metrics.UnCheckpointedCount} < {_options.UnCheckpointedCount}.");
            }
        }