public void Update(DailyTaskId Id, Action <DailyTaskAggregate> execute) { while (true) { EventStream eventStream = _eventStore.LoadEventStream(Id); DailyTaskAggregate dailyTask = new DailyTaskAggregate(eventStream.Events, goalService); execute(dailyTask); try { _eventStore.AppendToStream(Id, eventStream.Version, dailyTask.Changes); return; } catch (OptimisticConcurrencyException ex) { foreach (var dailyTaskEvent in dailyTask.Changes) { foreach (var actualEvent in ex.ActualEvents) { if (ConflictsWith(dailyTaskEvent, actualEvent)) { var msg = string.Format("Conflict between {0} and {1}", dailyTaskEvent, actualEvent); throw new RealConcurrencyException(msg, ex); } } } _eventStore.AppendToStream(Id, ex.ActualVersion, dailyTask.Changes); } } }
public Result <object> When(CreateProductCatalog cmd) { while (true) { var productCatalog = _factory.Create <ProductCatalogAggregate>(cmd.Id); try { _eventStore.AppendToStream <ProductCatalogAggregate>(cmd.Id, productCatalog.Version, productCatalog.Changes); return(new Result <object>(null, new List <Exception>())); } catch (EventStoreConcurrencyException ex) { HandleConcurrencyException(ex, productCatalog); return(new Result <object>(null, new List <Exception>() { ex })); } catch (Exception) { throw; } } }
public void Update(GoalId Id, Action <GoalAggreagate> execute) { while (true) { EventStream eventStream = _eventStore.LoadEventStream(Id); GoalAggreagate goal = new GoalAggreagate(eventStream.Events); execute(goal); try { _eventStore.AppendToStream(Id, eventStream.Version, goal.Changes); return; } catch (OptimisticConcurrencyException ex) { foreach (var goalEvent in goal.Changes) { foreach (var actualEvent in ex.ActualEvents) { if (ConflictsWith(goalEvent, actualEvent)) { var msg = string.Format("Conflict between {0} and {1}", goalEvent, actualEvent); throw new RealConcurrencyException(msg, ex); } } } _eventStore.AppendToStream(Id, ex.ActualVersion, goal.Changes); } } }
// method with direct call, as illustrated in the IDDD Book // Step 1: LockCustomerForAccountOverdraft method of // Customer Application Service is called public void LockCustomerForAccountOverdraft(CustomerId customerId, string comment) { // Step 2.1: Load event stream for Customer, given its id var stream = _eventStore.LoadEventStream(customerId); // Step 2.2: Build aggregate from event stream var customer = new Customer(stream.Events); // Step 3: call aggregate method, passing it arguments and pricing domain service customer.LockForAccountOverdraft(comment, _pricingService); // Step 4: commit changes to the event stream by id _eventStore.AppendToStream(customerId, stream.Version, customer.Changes); }
public void Execute <TIdent>(IEventStore eventStorage, TIdent id, Action <TAggregateRoot> execute) where TIdent : IIdentity { if (eventStorage == null) { throw new ArgumentNullException("eventStorage"); } if (id == null || id.Equals(default(TIdent))) { throw new ArgumentException("id is null or default value", "id"); } // Load event stream from the store var stream = eventStorage.LoadEventStream(id); // create new Customer aggregate from the history var aggregate = new TAggregateRoot(); aggregate.LoadsFromHistory(stream.Events); // execute delegated action Logger.DebugFormat("Executing Update on aggregate {0}", aggregate); execute(aggregate); // append resulting changes to the stream, expect the same version loaded before applying ddd logic if (aggregate.Changes.Any()) { Logger.DebugFormat("Saving {0} uncommited events on aggregate {1}", aggregate.Changes.Count, aggregate); eventStorage.AppendToStream(id, stream.Version, aggregate.Changes); } Logger.DebugFormat("Finished Update on {0}", aggregate); }
private static async Task AppendEvents(IEventStore eventStore, string streamId, int numberOfEvents) { for (int i = 0; i < numberOfEvents; i++) { var newStreamEvent = new NewStreamEvent(Guid.NewGuid(), "MyEvent", "{}"); await eventStore.AppendToStream(streamId, ExpectedVersion.Any, newStreamEvent); } }
public static Task AppendToStream( this IEventStore eventStore, string streamId, int expectedVersion, IEnumerable <NewStreamEvent> events) { return(eventStore.AppendToStream(streamId, expectedVersion, events.ToArray())); }
public static Task AppendToStream( this IEventStore eventStore, string streamId, int expectedVersion, NewStreamEvent newStreamEvent) { return(eventStore.AppendToStream(streamId, expectedVersion, new[] { newStreamEvent })); }
public void OnPost(Guid itemId, string newLocation) { var eventStream = _evnetStore.LoadEventStream("items"); var inventory = new Inventory(eventStream.Events); inventory.UpdateItemLocation(itemId, newLocation); _evnetStore.AppendToStream("items", inventory.PendingEvents, eventStream.Version); }
/// <summary> /// Extracts changes to the provided aggregate and appends them /// to an event stream. /// </summary> /// <param name="aggregate"></param> public async Task Save(TAggregate aggregate) { var streamName = StreamName(aggregate.Id); var changes = aggregate.GetChanges(); await _eventStore.AppendToStream(streamName, aggregate.Version, changes, Guid.NewGuid().ToString()); aggregate.ClearChanges(); }
private async Task Append <TAggregate>(TAggregate aggregate, long version) where TAggregate : Aggregate { await eventStore.AppendToStream <TAggregate>(aggregate.Id, aggregate.GetUncommitedChanges(), version); logger.LogInformation($"Append the {typeof(TAggregate).Name} aggregate by id: {aggregate.Id} and version {version}."); aggregate.Commit(); }
private async Task Save(ModeloViewModel viewModel) { try { var modelo = viewModel.GetModel(); try { eventStore.AppendToStream(modelo.Codigo, modelo.OriginalVersion, modelo.Changes); //foreach (var @event in modelo.Changes) //{ // await mediator.Send(@event); //} } catch (EventStoreConcurrencyException ex) { foreach (var failedEvent in modelo.Changes) { foreach (var succededEvent in ex.StoreEvents) { if (ConflictsWith(failedEvent, succededEvent)) { var message = $"Conflict between ${failedEvent} and {succededEvent}"; throw new RealConcurrencyException(ex); } } } eventStore.AppendToStream(modelo.Codigo, ex.StoreVersion, modelo.Changes); } OnItemSaved(viewModel); SetStatus($"Modelo '{modelo.Codigo}' salvo com sucesso."); } catch (Exception ex) { viewModel.Error = ex.Message; SetStatus(ex.Message); } }
/// <summary> /// 执行领域事件 /// </summary> public virtual void DoService() { //1.获得事件流 var stream = EventStore.LoadEventStream(Entity); //2.实体运行领域事件 Entity.AddEventStream(stream.Events); //3.保存事件 EventStore.AppendToStream(Entity, stream.Version, Entity.Changes); }
/// <inheritdoc /> public async Task Save <T>(T es) where T : class, TEventSourced { if (es == null) { return; } var events = es.GetUncommittedEvents().ToList(); if (events.Count == 0) { return; } var stream = await _streams.Find <T>(es.Id, _timeline.Id) ?? _streams.CreateEmpty(es, _timeline.Id); // _streams.GetOrAdd(es, _timeline.Id); if (stream.Version >= 0 && es.Version - events.Count < stream.Version) { throw new InvalidOperationException($"Stream ( {stream.Key}@{stream.Version} ) is ahead of aggregate root with version {es.Version - events.Count} saving {events.Count} events )"); } foreach (var e in events.Cast <Event>()) { if (e.Timestamp == default) { e.Timestamp = _timeline.Now; } if (e.LocalId == default) { e.LocalId = new EventId(Configuration.ReplicaName, e.Timestamp); } if (e.OriginId == default) { e.OriginId = e.LocalId; } e.Stream = stream.Key; e.Timeline = _timeline.Id; } await _eventStore.AppendToStream(stream, events); if (es is ISaga saga) { var commands = saga.GetUncommittedCommands(); foreach (var command in commands) { await _bus.CommandAsync(command); } } #if USE_ES_CACHE _cache[stream.Key] = es; #endif }
void Update(ICommand <RegistrationId> c, Action <RegistrationAggregate> action) { var stream = _eventStore.LoadEventStream(c.Id); var state = new RegistrationState(stream.Events); var agg = new RegistrationAggregate(state); using (Context.CaptureForThread()) { action(agg); _eventStore.AppendToStream(c.Id, stream.Version, agg.Changes); } }
void Update(ICommand <UserId> c, Action <UserAggregate> action) { var stream = _store.LoadEventStream(c.Id); var state = new UserState(stream.Events); var agg = new UserAggregate(state); using (Context.CaptureForThread()) { agg.ThrowOnInvalidStateTransition(c); action(agg); _store.AppendToStream(c.Id, stream.Version, agg.Changes); } }
public CommandEvent When(CreateProductCatalog cmd) { var productCatalog = _factory.Create <ProductCatalogAggregate>(cmd.Id); try { _eventStore.AppendToStream <ProductCatalogAggregate>(cmd.Id, productCatalog.Version, productCatalog.Changes, productCatalog.DomainEvents.ToArray()); return(new CommandEvent(OperationStatus.Success)); } catch (EventStoreConcurrencyException ex) { HandleConcurrencyException(ex, productCatalog); return(new CommandEvent(OperationStatus.Success)); } catch (Exception) { throw; } }
void Update(ICommand <SecurityId> c, Action <SecurityAggregate> action) { var eventStream = _eventStore.LoadEventStream(c.Id); var state = new SecurityState(eventStream.Events); var agg = new SecurityAggregate(state); using (Context.CaptureForThread()) { action(agg); _eventStore.AppendToStream(c.Id, eventStream.Version, agg.Changes); } }
public void SaveModule(Module module) { if (module.HasNoChanges) { return; } DoesModuleExist(module); _eventStore.AppendToStream(new EventStream($"module:{module.Id}", module.Version, module.Changes)); module.Changes.ForEach(@event => _eventPublisher.Publish(@event)); }
public IEnumerable <Item> Handle(GetItems query) { var eventStream = _evnetStore.LoadEventStream("items"); var inventory = new Inventory(eventStream.Events); if (inventory.Items is null) { inventory.Init(); _evnetStore.AppendToStream("items", inventory.PendingEvents, eventStream.Version); } return(inventory.Items); }
public void Execute <TIdent, TResult, TIdentCreated>(IEventStore eventStorage, TIdent id, Func <TResult, TAggregateRoot> execute, TIdentCreated createId) where TIdent : IIdentity where TResult : IAggregate, new() where TIdentCreated : IIdentity { if (eventStorage == null) { throw new ArgumentNullException("eventStorage"); } if (id == null || id.Equals(default(TIdent))) { throw new ArgumentException("id is null or default value", "id"); } if (createId == null || createId.Equals(default(TIdentCreated))) { throw new ArgumentException("createid is null or default value", "createId"); } EventStream stream = eventStorage.LoadEventStream(id); // create new Customer aggregate from the history var aggregate = new TResult(); aggregate.LoadsFromHistory(stream.Events); // execute delegated action Logger.DebugFormat("Executing UpdateAndCreateAggregate on aggregate {0}", aggregate); TAggregateRoot res = execute(aggregate); if (aggregate.Changes.Any()) { throw new Exception("You cannot modify more than one aggregate per command!"); } if (res != null && res.Changes.Any()) { Logger.DebugFormat("Saving {0} uncommited events on result aggregate {1}", res.Changes.Count, res); eventStorage.AppendToStream(createId, 0, res.Changes); Logger.DebugFormat("Finished Create on {0}", aggregate); return; } throw new InvalidOperationException("No aggregate created on execute"); }
public Result Handle(AddNewItemCommand cmd) { string fileName = null; if (cmd.ImageFile is object) { fileName = SaveFileToDisk(cmd); } var eventStream = _evnetStore.LoadEventStream("items"); var inventory = new Inventory(eventStream.Events); inventory.AddNewItem(cmd.ItemName, fileName is null ? "" : $"images/{fileName}"); _evnetStore.AppendToStream("items", inventory.PendingEvents, eventStream.Version); return(Result.Complete()); }
private static async Task RunLoadTest(CancellationTokenSource cts, IEventStore eventStore) { var tasks = new List <Task>(); int count = -1; for (int i = 0; i < Environment.ProcessorCount; i++) { var taskNumber = i; var task = Task.Run(async() => { while (!cts.IsCancellationRequested) { try { var eventNumber = Interlocked.Increment(ref count); var newStreamEvents = EventStoreAcceptanceTests .CreateNewStreamEvents(eventNumber * 2 + 1, eventNumber * 2 + 2); var info = $"{taskNumber} - {newStreamEvents[0].EventId}," + $"{newStreamEvents[1].EventId}"; Log.Logger.Information($"Begin {info}"); await eventStore.AppendToStream( $"stream-1", ExpectedVersion.Any, newStreamEvents, cts.Token); Log.Logger.Information($"End {info}"); Console.Write($"\r{eventNumber*2 + 2}"); } catch (Exception ex) when(!(ex is TaskCanceledException)) { cts.Cancel(); Log.Logger.Error(ex, ex.Message); Console.WriteLine(ex); Console.ReadKey(); } } }, cts.Token); tasks.Add(task); } await Task.WhenAll(tasks); }
public CloneFlow(string timeline, Time time, IEventStore <T> eventStore) : base(Configuration.DataflowOptions) { _inputBlock = new ActionBlock <IStream>( async s => { var version = await eventStore.GetVersion(s, time); if (version == ExpectedVersion.NoStream) { return; } var clone = s.Branch(timeline, version); await eventStore.AppendToStream(clone); Interlocked.Increment(ref _numberOfStreams); }, Configuration.DataflowOptions.ToDataflowBlockOptions(true)); // .ToExecutionBlockOption(true)); RegisterChild(_inputBlock); }
//Dessa forma, os métodos HasConflict e HandleConcurrencyException podem ser sobrescritos para se adaptar a questões de negócio protected virtual void HandleConcurrencyException <TAggregate>(EventStoreConcurrencyException ex, TAggregate root) where TAggregate : AggregateRoot <Guid> { foreach (var changeEvent in root.Changes) { foreach (var storeEvent in ex.StoreEvents) { if (HasConflict(changeEvent, storeEvent)) { var msg = string.Format("Conflict between {0} and {1}", changeEvent, changeEvent); throw new Exception(msg, ex); } } } var actualVersion = root.Version - root.Changes.Count; actualVersion += actualVersion; _eventStore.AppendToStream <TAggregate>(root.Id, actualVersion, root.Changes, root.DomainEvents.ToArray()); }
public void Save <TAggregate>(IAggregateRoot aggregate, int expectedVersion) where TAggregate : IAggregateRoot, new() { { var uncommitedChanges = aggregate.UncommitedChanges; if (uncommitedChanges.Any()) { lock (_lockStorage) { var item = new TAggregate(); if (expectedVersion != -1) { item = GetById <TAggregate>(aggregate.Guid); if (item.Version != expectedVersion) { throw new ConcurrencyException($"Aggregate {item.Guid} has been previously modified"); } } _eventStore.AppendToStream(uncommitedChanges); } } } }
public MergeFlow(ITimeline currentBranch, IEventStore <T> eventStore, IStreamLocator streamLocator, bool doMerge) : base(Configuration.DataflowOptions) { _inputBlock = new ActionBlock <IStream>( async s => { var version = ExpectedVersion.EmptyStream; var parentStream = s.Branch(currentBranch?.Id, ExpectedVersion.EmptyStream); var parent = s.Parent; while (parent != null && parent.Version > ExpectedVersion.EmptyStream) { parentStream = await streamLocator.Find(parent); version = parentStream.Version; if (currentBranch != null && (version > parent.Version && parent.Timeline == currentBranch.Id)) { var theseEvents = await eventStore .ReadStream <IEvent>(parentStream, parent.Version + 1, version - parent.Version) .Select(e => e.MessageId).ToList(); var thoseEvents = await eventStore .ReadStream <IEvent>(s, parent.Version + 1, version - parent.Version) .Select(e => e.MessageId).ToList(); if (theseEvents.Zip(thoseEvents, (e1, e2) => (e1, e2)).Any(x => x.Item1 != x.Item2)) { throw new InvalidOperationException( $"{currentBranch?.Id} timeline has moved on in the meantime, aborting...( {parentStream.Key} : {version} > {parent.Version} )"); } return; } if (s.Version == version) { return; } if (parentStream.Timeline == currentBranch?.Id) { break; } parent = parent.Parent; } if (!doMerge) { return; } Interlocked.Increment(ref _numberOfStreams); var events = await eventStore.ReadStream <IEvent>(s, version + 1, s.Version - version).ToList(); foreach (var e in events.OfType <Event>()) { e.Stream = parentStream.Key; } Interlocked.Add(ref _numberOfEvents, events.Count); await eventStore.AppendToStream(parentStream, events, false); }, Configuration.DataflowOptions.ToDataflowBlockOptions(true)); // .ToExecutionBlockOption(true)); RegisterChild(_inputBlock); }
public void Handle(User_CreateCommand message) { var user = new UserAR(message.UserId, message.Name, message.Password); _eventStore.AppendToStream(message.UserId, 0, user.Changes); }
public void Save(IAggregateRoot aggregateRoot, IEnumerable <object> uncommitedEvents) { _eventStore.AppendToStream(aggregateRoot.AggregateId.ToString(), uncommitedEvents); }