public void All_async_handlers_performs_in_parralel() { Sys.InitLocalTransportExtension(); var delayActor = Sys.ActorOf(Props.Create(() => new EchoSleepActor(TimeSpan.FromMilliseconds(100), TestActor))); var catalog = new HandlersDefaultProcessor(); catalog.Add <BalloonCreated>(new FireAndForgetActorMessageProcessor(delayActor)); catalog.Add <BalloonTitleChanged>(new FireAndForgetActorMessageProcessor(delayActor)); var actor = Sys.ActorOf(Props.Create(() => new HandlersPipeActor(catalog, TestActor))); var sampleAggregateCreatedEvent = new BalloonCreated("1", Guid.NewGuid().ToString()); var sampleAggregateChangedEvent = new BalloonTitleChanged("1", Guid.NewGuid().ToString()); actor.Tell(new MessageMetadataEnvelop(sampleAggregateCreatedEvent)); //HandlersProcessActor should notify next step - process actor that work is done ExpectMsg <IMessageMetadataEnvelop>(m => m.Message is DomainEvent); ExpectMsg <AllHandlersCompleted>(); //but handlers will finish their work later in undefined sequence actor.Tell(new MessageMetadataEnvelop(sampleAggregateChangedEvent)); ExpectMsg <IMessageMetadataEnvelop>(m => m.Message is DomainEvent); //HandlersProcessActor should notify sender (TestActor) of initial messages that work is done ExpectMsg <AllHandlersCompleted>(); }
public static BalloonCatalogItem ToCatalogItem(this BalloonCreated e) { return(new BalloonCatalogItem() { BalloonId = e.SourceId, LastChanged = e.CreatedTime, Title = e.Value }); }
public void Process_change_state_after_transitions() { var domainEventA = new BalloonCreated("1", Guid.NewGuid().ToString(), DateTime.Now, _processId); _processActor.Ref.Tell(MessageMetadataEnvelop.New(domainEventA)); var msg = ExpectMsg <ProcessTransited>(); Assert.Equal(domainEventA.SourceId, ((TestState)msg.NewProcessState).ProcessingId); }
public async Task Handle(BalloonCreated msg, IMessageMetadata metadata = null) { _log.Debug("Projecting balloon catalog from message {@msg}", msg); using (var context = _contextCreator()) { context.BalloonCatalog.Add(msg.ToCatalogItem()); await context.SaveChangesAsync(); _publisher.Publish(new BalloonCreatedNotification() { BallonId = msg.SourceId }, metadata.CreateChild(Guid.NewGuid().ToString(), _readModelUpdatedProcessEntry)); } }
public void Given_no_processors_pipe_still_reply_with_completed_messages() { var catalog = new HandlersDefaultProcessor(); Sys.InitLocalTransportExtension(); var actor = Sys.ActorOf(Props.Create(() => new HandlersPipeActor(catalog, TestActor))); var sampleAggregateCreatedEvent = new BalloonCreated("1", Guid.NewGuid().ToString()); actor.Tell(MessageMetadataEnvelop.New(sampleAggregateCreatedEvent, MessageMetadata.Empty)); //HandlersPipeActor should notify next step - process actor that work is done ExpectMsg <IMessageMetadataEnvelop <DomainEvent> >(); //HandlersPipeActor should notify sender (TestActor) of initial messages that work is done ExpectMsg <AllHandlersCompleted>(); }
public void Process_actor_process_one_message_in_time() { var domainEventA = new BalloonCreated("1", Guid.NewGuid().ToString(), DateTime.Now, _processId); var domainEventB = new BalloonTitleChanged("2", Guid.NewGuid().ToString(), DateTime.Now, _processId); _processActor.Tell(MessageMetadataEnvelop.New(domainEventA, MessageMetadata.Empty)); _processActor.Tell(MessageMetadataEnvelop.New(domainEventB, MessageMetadata.Empty)); //A was received first and should be processed first var msg = ExpectMsg <ProcessTransited>(); Assert.Equal(domainEventA.SourceId, ((TestState)msg.NewProcessState).ProcessingId); //B should not be processed after A is completed var msgB = ExpectMsg <ProcessTransited>(); Assert.Equal(domainEventB.SourceId, ((TestState)msgB.NewProcessState).ProcessingId); }
public async Task Given_only_aggregate_events_persisted_it_can_be_loaded(IRepository <DomainEvent> eventRepo, AggregateRepository aggrRepo) { try { _sourceId = Guid.NewGuid().ToString(); _created = new BalloonCreated("initial value", _sourceId); _changed = new BalloonTitleChanged("changed value", _sourceId); var persistenceId = EntityActorName.New <Balloon>(_sourceId).ToString(); await eventRepo.Save(persistenceId, _created, _changed); _aggregate = await aggrRepo.LoadAggregate <Balloon>(_sourceId); Assert.Equal(_sourceId, _aggregate.Id); Assert.Equal(_changed.Value, _aggregate.Title); } finally { eventRepo.Dispose(); aggrRepo.Dispose(); } }
public async Task All_Processes_performs_linear_and_results_from_all_processes_are_gathered() { var processAId = Guid.NewGuid().ToString(); _output.WriteLine("Process A:" + processAId); var testProcessActorA = Sys.ActorOf(Props.Create(() => new TestProcessActor(TestActor, processAId, TimeSpan.FromMilliseconds(1000)))); var processBId = Guid.NewGuid().ToString(); _output.WriteLine("Process B:" + processBId); var testProcessActorB = Sys.ActorOf(Props.Create(() => new TestProcessActor(TestActor, processBId, TimeSpan.FromMilliseconds(50)))); var processCId = Guid.NewGuid().ToString(); _output.WriteLine("Process C:" + processCId); var testProcessActorC = Sys.ActorOf(Props.Create(() => new TestProcessActor(TestActor, processCId, TimeSpan.FromMilliseconds(50)))); var catalog = new ProcessesDefaultProcessor(); catalog.Add <BalloonCreated>(new SyncProcessManagerProcessor(testProcessActorA)); catalog.Add <BalloonTitleChanged>(new SyncProcessManagerProcessor(testProcessActorB)); catalog.Add <BalloonTitleChanged>(new SyncProcessManagerProcessor(testProcessActorC)); var balloonCreated = new BalloonCreated("1", Guid.NewGuid().ToString()); var balloonTitleChanged = new BalloonTitleChanged("2", Guid.NewGuid().ToString()); //var resultA = await catalog.Process(MessageMetadataEnvelop.New<DomainEvent>(balloonCreated)); //var resultB = await catalog.Process(MessageMetadataEnvelop.New<DomainEvent>(balloonTitleChanged)); var processPipeActor = Sys.ActorOf(Props.Create(() => new ProcessesPipeActor(catalog))); await processPipeActor.Ask <Initialized>(new Initialize(TestActor)); processPipeActor.Tell(MessageMetadataEnvelop.New <DomainEvent>(balloonCreated)); processPipeActor.Tell(MessageMetadataEnvelop.New <DomainEvent>(balloonTitleChanged)); //process pipe will process domain event linear on each message //but for don't wait for each message execution end, so first will complete process of second message - balloonTitleChanged //after process pipe will proceed with balloonTitleChanged event, pass it linear to two left process managers var transited = ExpectMsg <ProcessTransited>(TimeSpan.FromSeconds(600)); var testCommand = transited.ProducedCommands.OfType <TestCommand>().First(); Assert.Equal(processBId, testCommand.ProcessId); transited = ExpectMsg <ProcessTransited>(); testCommand = transited.ProducedCommands.OfType <TestCommand>().First(); Assert.Equal(processCId, testCommand.ProcessId); //after it process pipe is finished with ballon created message processing, gathering results //and sending it to commandPipe (testActor) var cmdB = ExpectMsg <MessageMetadataEnvelop <ICommand> >(); Assert.Equal(processBId, cmdB.Message.ProcessId); var cmdC = ExpectMsg <MessageMetadataEnvelop <ICommand> >(); Assert.Equal(processCId, cmdC.Message.ProcessId); //than it will report end of domain event processing ExpectMsg <ProcessesTransitComplete>(); //than slow processing of first message will finish //test process actors sends to us messages on complete //wait for test process actor transit on first event transited = ExpectMsg <ProcessTransited>(); testCommand = transited.ProducedCommands.OfType <TestCommand>().First(); Assert.Equal(processAId, testCommand.ProcessId); var cmdA = ExpectMsg <MessageMetadataEnvelop <ICommand> >(); Assert.Equal(processAId, cmdA.Message.ProcessId); //process pipe has only one handler for balloonCreated, so it will finish processing //and send us a message ExpectMsg <ProcessesTransitComplete>(); }
//can change to Apply<T> call in constructor, left for testing public void Apply(BalloonCreated e) { Id = e.Id; Title = e.Value; }