DispatchDomainEvents(IEventSourced <TAggregateId> aggregate, TransportMessage <TRequest, TAggregateId> transRequest ) { var hasError = false; var results = new Dictionary <DomainEvent <TAggregateId>, DomainResult>(); foreach (var @event in aggregate.ReleaseEvents()) { if (!hasError) { var result = await this.eventsDispatcher.DispatchEvent( new TransportMessage <DomainEvent <TAggregateId>, TAggregateId>( @event, transRequest.CorrelationId, transRequest.UserId, transRequest.RequestTimestamp)); results.Add(@event, result); if (result.HasError) { hasError = true; } } else { results.Add(@event, DomainResult.Skipped); } } return(results); }
public IStream GetOrAdd(IEventSourced es) { var key = Key(es); var stream = new Stream(key, es.Version, es.GetType()); return(_streams.GetOrAdd(key, stream)); }
public static string BuildParentsString(this IEventSourced parent) { var parents = parent.Stream.Parents.ToList(); parents.Add(parent.Id); return(parents.BuildParentsString()); }
public static IEventSourced AndOne <TEvent>(this IEventSourced aggregate) where TEvent : IEvent { var singleEvent = aggregate.PendingEvents.OfType <TEvent>().Single(); return(aggregate); }
public static IEnumerable <Id> BuildParents(this IEventSourced parent) { var parents = parent.Stream.Parents.ToList(); parents.Add(parent.Id); return(parents); }
protected override Task <Dictionary <DomainEvent <PublicSchemeId>, DomainResult> > DispatchDomainEvents( IEventSourced <PublicSchemeId> aggregate, TransportMessage <DomainRequest <PublicSchemeId>, PublicSchemeId> transRequest) { aggregate.Should().BeSameAs(this.testScheme); this.dispatchDomainEvents_CallCount++; return(base.DispatchDomainEvents(aggregate, transRequest)); }
internal static void SetAggregate( this IEvent @event, IEventSourced aggregate) => @event.IfTypeIs <IHaveExtensibleMetada>() .ThenDo(e => ((object)e.Metadata) .IfTypeIs <IDictionary <string, object> >() .ThenDo(metadata => { metadata["Aggregate"] = aggregate; }));
public virtual void OfAggregate(IEventSourced <TStreamId> aggregate) { if (aggregate.StreamId.Equals(default(TStreamId)) || !aggregate.StreamId.Equals(StreamId)) { throw AggregateIdNotMatchException.GetAggregateIdNotMatchExceptionFromAggregateAndEvent(aggregate, this); } EventVersion = aggregate.CurrentVersion; }
public static IEventSourced AndNotAny <TEvent>(this IEventSourced aggregate) where TEvent : IEvent { if (aggregate.PendingEvents.OfType <TEvent>().Any()) { throw new InvalidOperationException($"Not expected any '{typeof(TEvent).Name}' event type but there is/are {aggregate.PendingEvents.OfType<TEvent>().Count()} event/s of that type."); } return(aggregate); }
public void Save(IEventSourced eventSourced, Envelope <ICommand> command) { Assertions.NotNull(eventSourced, "eventSourced"); Assertions.NotNull(command, "command"); var eventSourcedType = eventSourced.GetType(); var sourceInfo = new SourceInfo(eventSourced.Id, eventSourcedType); var changedEvents = eventSourced.GetChanges(); var saved = false; try { if (_eventStore.Save(sourceInfo, changedEvents, command.MessageId)) { if (LogManager.Default.IsDebugEnabled) { LogManager.Default.DebugFormat( "Persistent domain events successfully. aggregateRootType:{0},aggregateRootId:{1},version:{2}~{3}.", eventSourcedType.FullName, eventSourced.Id, changedEvents.Min(p => p.Version), changedEvents.Max(p => p.Version)); } saved = true; } } catch (Exception ex) { LogManager.Default.Error(ex, "Persistent domain events failed. aggregateRootType:{0},aggregateRootId:{1},version:{2}~{3}.", eventSourcedType.FullName, eventSourced.Id, changedEvents.Min(p => p.Version), changedEvents.Max(p => p.Version)); throw ex; } if (!saved) { //由该命令产生的事件如果已保存,则取出之前的事件重新发送 changedEvents = _eventStore.Find(sourceInfo, command.MessageId); _eventBus.Publish(sourceInfo, changedEvents, command); return; } try { _cacheProvider.GetCache(GetCacheRegion(eventSourcedType)).Put(GetCacheKey(eventSourcedType, eventSourced.Id), eventSourced); } catch (Exception ex) { LogManager.Default.Warn(ex, "Failed to refresh aggregate root to memory cache. aggregateRootType:{0},aggregateRootId:{1}.", eventSourcedType.FullName, eventSourced.Id); } _eventBus.Publish(sourceInfo, changedEvents, command); }
public bool ShouldCreateSnapshot(IEventSourced eventSourced) { var isShould = false; if ((eventSourced.Version + 1) % snapshotIntervalInEvents == 0) { isShould = true; } return(isShould); }
public async Task Handle(ConflictingEvents conflicts, IMessageHandlerContext ctx) { // Hydrate the entity, include all his parents IEventSourced parentBase = null; foreach (var parent in conflicts.Parents) { parentBase = await GetBase(conflicts.Bucket, parent.Item1, parent.Item2, parentBase).ConfigureAwait(false); } var target = await GetBase(conflicts.Bucket, conflicts.EntityType, conflicts.StreamId, parentBase).ConfigureAwait(false); var stream = target.Stream; Logger.Write(LogLevel.Info, () => $"Weakly resolving {conflicts.Events.Count()} conflicts on stream [{conflicts.StreamId}] type [{target.GetType().FullName}] bucket [{target.Stream.Bucket}]"); // No need to pull from the delayed channel or hydrate as below because this is called from the Delayed system which means // the conflict is not in delayed cache and GetBase above pulls the latest stream Logger.Write(LogLevel.Debug, () => $"Merging {conflicts.Events.Count()} conflicted events"); try { foreach (var u in conflicts.Events) { target.Conflict(u.Event as IEvent, metadata: new Dictionary <string, string> { { "ConflictResolution", ConcurrencyConflict.ResolveWeakly.ToString() } }); } } catch (NoRouteException e) { Logger.Write(LogLevel.Info, () => $"Failed to resolve conflict: {e.Message}"); throw new ConflictResolutionFailedException("Failed to resolve conflict", e); } Logger.Write(LogLevel.Info, () => "Successfully merged conflicted events"); if (stream.StreamVersion != stream.CommitVersion && target is ISnapshotting && ((ISnapshotting)target).ShouldTakeSnapshot()) { Logger.Write(LogLevel.Debug, () => $"Taking snapshot of [{target.GetType().FullName}] id [{target.Id}] version {stream.StreamVersion}"); var memento = ((ISnapshotting)target).TakeSnapshot(); stream.AddSnapshot(memento); } // Dont call stream.Commit we are inside a UOW in this method it will do the commit for us }
public static IEventSourced AndAtLeastOne <TEvent>(this IEventSourced aggregate) where TEvent : IEvent { var hasEvents = aggregate.PendingEvents.OfType <TEvent>().Any(); if (hasEvents) { return(aggregate); } else { throw new InvalidOperationException($"Aggregate of type {aggregate.GetType().Name} does not generated any event of type {typeof(TEvent).Name} so far."); } }
public static IEventSourced ThenExpectSingle <TEvent>(this IEventSourced aggregate) { var count = aggregate.PendingEvents.OfType <TEvent>().Count(); if (count <= 0) { throw new InvalidOperationException($"There was expected to find a single event of type '{typeof(TEvent).Name}' but none were found."); } else if (count == 1) { return(aggregate); } throw new InvalidOperationException($"There was expected to find a single event of type '{typeof(TEvent).Name}' but there where found {count} events of that type."); }
public async Task SaveAsync(TAggregate aggregate) { try { IEventSourced <TAggregateId> aggregateEventSourcedView = aggregate; foreach (var evt in aggregateEventSourcedView.UncommittedEvents) { await _eventStore.AddEventAsync(evt).ConfigureAwait(false); // TODO : create PublishEventAsync method to make this call async PublishEvent(evt); } aggregateEventSourcedView.ClearUncommittedEvents(); } catch (EventStoreNotReachableException ex) { throw new RepositoryException(CommunicationImpossibleWithPersistenceBackend, ex); } }
public void Save(TAggregate aggregate) { try { IEventSourced <TAggregateId> aggregateEventSourcedView = aggregate; var versionFromStore = _eventStore.GetNextExpectedVersion(aggregate.AggregateId); long count = 0; foreach (var evt in aggregateEventSourcedView.UncommittedEvents) { VersionGuard(versionFromStore, evt); versionFromStore = _eventStore.AddEvent(evt); PublishEvent(evt); count++; } aggregateEventSourcedView.ClearUncommittedEvents(); } catch (EventStoreNotReachableException ex) { throw new RepositoryException(CommunicationImpossibleWithPersistenceBackend, ex); } }
public async Task <TAggregate> GetByIdAsync(TAggregateId id) { try { var aggregate = _emptyAggregateFactory.GetEmptyAggregate(); IEventSourced <TAggregateId> aggregateEventSourcedView = aggregate; foreach (var evt in await _eventStore.ReadEventsAsync(id)) { aggregateEventSourcedView.ProcessEvent(evt.DomainEvent, evt.Version); } return(aggregate); } catch (AggregateNotFoundEventStoreException) { return(null); } catch (EventStoreNotReachableException ex) { throw new RepositoryException(CommunicationImpossibleWithPersistenceBackend, ex); } }
public TAggregate GetById(TAggregateId id) { try { var aggregate = _emptyAggregateFactory.GetEmptyAggregate(); IEventSourced <TAggregateId> aggregateEventSourcedView = aggregate; foreach (var evt in _eventStore.ReadEvents(id)) { //aggregate.RaiseEvent(evt.DomainEvent); aggregateEventSourcedView.ProcessEvent(evt.DomainEvent, evt.Version); } aggregateEventSourcedView.ClearUncommittedEvents(); return(aggregate); } catch (AggregateNotFoundEventStoreException) { return(null); } catch (EventStoreNotReachableException ex) { throw new RepositoryException(CommunicationImpossibleWithPersistenceBackend, ex); } }
/// <summary> /// 删除该聚合根下的溯源事件 /// </summary> public void Delete(IEventSourced aggregateRoot) { this.Delete(aggregateRoot.GetType(), aggregateRoot.Id); }
/// <summary> /// 保存聚合事件。 /// </summary> public void Save(IEventSourced aggregateRoot, string correlationId) { if (string.IsNullOrWhiteSpace(correlationId)) { if (_logger.IsWarnEnabled) _logger.Warn("Not use command to modify the state of the aggregate root."); } var aggregateRootType = aggregateRoot.GetType(); var aggregateRootId = aggregateRoot.Id; var events = aggregateRoot.GetEvents(); var key = new SourceKey(aggregateRootId, aggregateRootType); if (_eventStore.Save(key, correlationId, () => events.Select(Serialize))) { if (_logger.IsDebugEnabled) _logger.DebugFormat("Domain events persistent completed. aggregateRootId:{0}, aggregateRootType:{1}, commandId:{2}.", aggregateRootId, aggregateRootType.FullName, correlationId); _cache.Set(aggregateRoot, aggregateRoot.Id); } else { events = _eventStore.FindAll(key, correlationId).Select(Deserialize).OfType<IVersionedEvent>().OrderBy(p => p.Version); if (_logger.IsDebugEnabled) _logger.DebugFormat("The command generates events have been saved, load from storage. aggregateRootId:{0}, aggregateRootType:{1}, commandId:{2}.", aggregateRootId, aggregateRootType.FullName, correlationId); } List<IEvent> pendingEvents = new List<IEvent>(); if (string.IsNullOrWhiteSpace(correlationId)) { pendingEvents.AddRange(events); } else { pendingEvents.Add(Convert(key, correlationId, events)); } var eventPublisher = aggregateRoot as IEventPublisher; if (eventPublisher != null) { var otherEvents = eventPublisher.Events.Where(p => !(p is IVersionedEvent)); pendingEvents.AddRange(otherEvents); } _eventBus.Publish(pendingEvents); var snapshot = Serialize(key, aggregateRoot); if (!_snapshotPolicy.ShouldbeCreateSnapshot(snapshot)) return; try { if (_snapshotStore.Save(snapshot) && _logger.IsDebugEnabled) _logger.DebugFormat("make snapshot completed. aggregateRootId:{0},aggregateRootType:{1},version:{2}.", aggregateRootId, aggregateRootType.FullName, aggregateRoot.Version); } catch (Exception ex) { if (_logger.IsWarnEnabled) _logger.Warn(ex, "snapshot persistent failed. aggregateRootId:{0},aggregateRootType:{1},version:{2}.", aggregateRootId, aggregateRootType.FullName, aggregateRoot.Version); } }
public static IEnumerable <TEvent> EventsOfType <TEvent>(this IEventSourced aggregate) where TEvent : IEvent { return(aggregate.PendingEvents.OfType <TEvent>().AsEnumerable()); }
public void OfAggregate(IEventSourced <int> aggregate) { throw new NotImplementedException(); }
private static string GetStandardizedErrorMessage <TAggregateId>(IEventSourced <TAggregateId> aggregate, DomainEventBase <TAggregateId> evt) => $"The StreamId {aggregate.StreamId} of the aggregate don't match the recorded StreamId {evt.StreamId} of the Event.";
public static AggregateIdNotMatchException GetAggregateIdNotMatchExceptionFromAggregateAndEvent <TAggregateId>(IEventSourced <TAggregateId> aggregate, DomainEventBase <TAggregateId> evt, Exception inner) => new AggregateIdNotMatchException(GetStandardizedErrorMessage(aggregate, evt), inner);
public static TEvent SingleEvent <TEvent>(this IEventSourced aggregate) where TEvent : IEvent { return((TEvent)aggregate.Events.Single()); }
internal static IEnumerable <string> ETags(this IEventSourced eventSourced) { return(eventSourced.IfTypeIs <EventSourcedAggregate>() .Then(a => a.ETags()) .Else(() => new string[0])); }
/// <summary> /// 保存聚合事件。 /// </summary> public void Save(IEventSourced aggregateRoot, string correlationId) { if (string.IsNullOrWhiteSpace(correlationId)) { if (_logger.IsWarnEnabled) _logger.Warn("Not use command to modify the state of the aggregate root."); } var aggregateRootType = aggregateRoot.GetType(); var aggregateRootId = aggregateRoot.Id; var events = aggregateRoot.GetEvents(); var key = new SourceKey(aggregateRootId, aggregateRootType); if (!_eventStore.EventPersisted(key, correlationId)) { _eventStore.Save(key, correlationId, events.Select(Serialize)); if (_logger.IsInfoEnabled) _logger.InfoFormat("sourcing events persistent completed. aggregateRootId:{0},aggregateRootType:{1}.", aggregateRootId, aggregateRootType.FullName); } else { events = _eventStore.FindAll(key, correlationId).Select(Deserialize).OfType<IVersionedEvent>().OrderBy(p => p.Version); if (_logger.IsInfoEnabled) _logger.InfoFormat("the command generates events have been saved, load from storage. command id:{0}", correlationId); } if (string.IsNullOrWhiteSpace(correlationId)) { _eventBus.Publish(events); } else { _eventBus.Publish(Convert(key, correlationId, events)); } var eventPublisher = aggregateRoot as IEventPublisher; if (eventPublisher != null) { eventPublisher.Events.ForEach(item => { if (item is IVersionedEvent) return; }); } //if (_logger.IsInfoEnabled) // _logger.InfoFormat("publish all events. event:{0}", _textSerializer.Serialize(events)); _cache.Set(aggregateRoot, aggregateRoot.Id); var snapshot = Serialize(key, aggregateRoot); if (!_snapshotPolicy.ShouldbeCreateSnapshot(snapshot)) return; try { if (_snapshotStore.Save(snapshot) && _logger.IsInfoEnabled) _logger.InfoFormat("make snapshot completed. aggregateRootId:{0},aggregateRootType:{1},version:{2}.", aggregateRootId, aggregateRootType.FullName, aggregateRoot.Version); } catch (Exception ex) { if (_logger.IsWarnEnabled) _logger.Warn(ex, "snapshot persistent failed. aggregateRootId:{0},aggregateRootType:{1},version:{2}.", aggregateRootId, aggregateRootType.FullName, aggregateRoot.Version); } }
private Stream Serialize(SourceKey sourceKey, IEventSourced aggregateRoot) { return new Stream() { Key = sourceKey, Version = aggregateRoot.Version, Payload = _binarySerializer.Serialize(aggregateRoot) }; }
public override void OfAggregate(IEventSourced <int> aggregate) => EventVersion = aggregate.CurrentVersion;
public static TEvent OneEventOfType <TEvent>(this IEventSourced aggregate) where TEvent : IEvent { return(aggregate.PendingEvents.OfType <TEvent>().Single()); }
/// <summary> /// Initializes a new instance of the <see cref="Stream"/> class. /// </summary> /// <param name="es">Event sourced instance</param> /// <param name="timeline">Target timeline</param> public Stream(IEventSourced es, string timeline = "") : this(es.Id, es.GetType().Name, ExpectedVersion.NoStream, timeline) { }
public Guid Key(IEventSourced es) { return(es.Id); }
public static string GetEventStoreStream <TKey>(this IEventSourced <TKey> aggregate) { return(string.Format("{0}-{1}", aggregate.GetType().Name, aggregate.Id)); }
public bool ShouldCreateSnapshot(IEventSourced eventSourced) { return(false); }