public IStream GetOrAdd(IEventSourced es) { var key = Key(es); var stream = new Stream(key, es.Version, es.GetType()); return(_streams.GetOrAdd(key, stream)); }
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 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."); } }
private async Task <IEventSourced> GetBase(string bucket, string type, Id id, IEventSourced parent = null) { var entityType = Type.GetType(type, false, true); if (entityType == null) { Logger.Error($"Received conflicting events message for unknown type {type}"); throw new ArgumentException($"Received conflicting events message for unknown type {type}"); } // We have the type name, hack the generic parameters to build Entity if (parent == null) { var method = typeof(IUnitOfWork).GetMethod("For", new Type[] {}).MakeGenericMethod(entityType); var repo = method.Invoke(_uow, new object[] { }); method = repo.GetType().GetMethod("Get", new Type[] { typeof(string), typeof(Id) }); // Note: we can't just cast method.Invoke into Task<IEventSourced> because Task is not covariant // believe it or not this is the easiest solution var task = (Task)method.Invoke(repo, new object[] { bucket, id }); await task.ConfigureAwait(false); return(task.GetType().GetProperty("Result").GetValue(task) as IEventSourced); } else { var method = typeof(IUnitOfWork).GetMethods() .Single(x => x.Name == "For" && x.GetParameters().Length == 1) .MakeGenericMethod(parent.GetType(), entityType); var repo = method.Invoke(_uow, new object[] { parent }); method = repo.GetType().GetMethod("Get", new Type[] { typeof(Id) }); var task = (Task)method.Invoke(repo, new object[] { id }); await task.ConfigureAwait(false); return(task.GetType().GetProperty("Result").GetValue(task) as IEventSourced); } }
public static string GetEventStoreStream <TKey>(this IEventSourced <TKey> aggregate) { return(string.Format("{0}-{1}", aggregate.GetType().Name, aggregate.Id)); }
/// <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) { }
/// <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); } }
/// <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.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); } }
/// <summary> /// 保存聚合事件。 /// </summary> public void Save(IEventSourced aggregateRoot, string correlationId = null) { var events = aggregateRoot.GetEvents(); if (events.IsEmpty()) { return; } var aggregateRootType = aggregateRoot.GetType(); int aggregateRootTypeCode = _typeCodeProvider.GetTypeCode(aggregateRootType); string aggregateRootId = aggregateRoot.Id.ToString(); if (!_eventStore.IsExist(correlationId)) { var sourcedEvents = events.Select(@event => new EventData() { AggregateRootId = aggregateRootId, AggregateRootTypeCode = aggregateRootTypeCode, Version = @event.Version, CorrelationId = correlationId, Payload = _serializer.Serialize(@event) }).ToArray(); _eventStore.Append(sourcedEvents); _logger.Info("sourcing events persistent completed. aggregateRootId:{0},aggregateRootType:{1}.", aggregateRootId, aggregateRootType.FullName); _cache.Set(aggregateRoot, aggregateRoot.Id); } else { events = _eventStore.FindAll(correlationId).Select(Deserialize); _logger.Info("the command generates events have been saved, load from storage. command id:{0}", correlationId); } _eventBus.Publish(new EventStream { AggregateRootId = aggregateRootId, AggregateRootTypeCode = aggregateRootTypeCode, CommandId = correlationId, StartVersion = events.Min(item => item.Version), EndVersion = events.Max(item => item.Version), Events = events.OfType <IEvent>().ToArray() }); _logger.Info("publish all events. event ids: [{0}]", string.Join(",", events.Select(@event => @event.Id).ToArray())); if (_snapshotStore.StorageEnabled) { var snapshot = new SnapshotData(aggregateRootTypeCode, aggregateRootId) { Data = _serializer.Serialize(aggregateRoot), Version = aggregateRoot.Version }; _snapshotStore.Save(snapshot).ContinueWith(task => { if (task.Status == TaskStatus.Faulted) { _logger.Error(task.Exception, "snapshot persistent failed. aggregateRootId:{0},aggregateRootType:{1},version:{2}.", aggregateRootId, aggregateRootType.FullName, aggregateRoot.Version); } }); //Task.Factory.StartNew(() => { // try { // _snapshotStore.Save(snapshot); // } // catch (Exception ex) { // _logger.Error(ex, "snapshot persistent failed. aggregateRootId:{0},aggregateRootType:{1},version:{2}.", aggregateRootId, aggregateRootType.FullName, aggregateRoot.Version); // } //}); } }
/// <summary> /// 删除聚合相关的事件。 /// </summary> public void Remove(IEventSourced aggregate) { this.Remove(aggregate.GetType(), aggregate.Id); }