public async Task MinionFound() { var id = new ClaptrapIdentity("1", "2"); var store = new ClaptrapDesignStore(); var mainDesign = new ClaptrapDesign { ClaptrapTypeCode = id.TypeCode }; store.AddOrReplace(mainDesign); var minionDesign = new ClaptrapDesign { ClaptrapTypeCode = "minion", ClaptrapMasterDesign = mainDesign }; store.AddOrReplace(minionDesign); using var mocker = AutoMock.GetLoose(builder => { builder.RegisterInstance(store) .AsImplementedInterfaces() .SingleInstance(); }); mocker.Mock <IActorProxyFactory>() .Setup(x => x.Create(new ActorId(id.Id), minionDesign.ClaptrapTypeCode, It.IsAny <ActorProxyOptions>())) .Verifiable(); var daprMinionActivator = mocker.Create <DaprMinionActivator>(); // act await daprMinionActivator.WakeAsync(id); }
public async Task ExceptionAndCompensate() { var container = CreateContainer(); await using var scope = container.BeginLifetimeScope(); var masterIdentity = new ClaptrapIdentity(Guid.NewGuid().ToString(), "TestCode"); await using var claptrap = scope.CreateSagaClaptrap(masterIdentity, "testFlow", typeof(TestFlowData)); var sagaFlow = SagaFlowBuilder.Create() .WithStep <TestStep1, CompensateStep1>() .WithStep <ExceptionStep, CompensateStep2>() .WithUserData(new TestFlowData()) .Build(); var claptrapAccessor = scope.Resolve <IClaptrapAccessor>(); await claptrap.RunAsync(sagaFlow); var claptrapStateData = (SagaStateData <TestFlowData>)claptrapAccessor.Claptrap.State.Data; var flowState = claptrapStateData.SagaFlowState; flowState.IsCompleted.Should().BeFalse(); flowState.IsCompensating.Should().BeFalse(); flowState.IsCompensated.Should().BeTrue(); flowState.StepStatuses.Should().Equal(StepStatus.Completed, StepStatus.Error); flowState.CompensateStepStatuses.Should().Equal(StepStatus.Completed, StepStatus.Completed); var flowData = (TestFlowData)claptrapStateData.GetUserData(); flowData.Test1.Should().BeFalse(); flowData.Test2.Should().BeFalse(); await claptrap.RunAsync(sagaFlow); }
public async Task MinionNotFound() { var id = new ClaptrapIdentity("1", "2"); var store = new ClaptrapDesignStore(); var mainDesign = new ClaptrapDesign { ClaptrapTypeCode = id.TypeCode }; store.AddOrReplace(mainDesign); using var mocker = AutoMock.GetLoose(builder => { builder.RegisterInstance(store) .AsImplementedInterfaces() .SingleInstance(); }); var daprMinionActivator = mocker.Create <DaprMinionActivator>(); // act await daprMinionActivator.WakeAsync(id); mocker.Mock <IActorProxyFactory>() .Verify(x => x.Create(It.IsAny <ActorId>(), It.IsAny <string>(), It.IsAny <ActorProxyOptions>()), Times.Never); }
public async Task SaveEventAsync(string accountId, int count) { using var lifetimeScope = BuildService().CreateScope(); var logger = lifetimeScope.ServiceProvider.GetRequiredService <ILogger <QuickSetupTestBase> >(); var factory = (ClaptrapFactory)lifetimeScope.ServiceProvider.GetRequiredService <IClaptrapFactory>(); var id = new ClaptrapIdentity(accountId, Codes.Account); await using var buildClaptrapLifetimeScope = factory.BuildClaptrapLifetimeScope(id); var saver = buildClaptrapLifetimeScope.Resolve <IEventSaver>(); var tasks = Enumerable.Range(Defaults.EventStartingVersion, count) .Select(x => saver.SaveEventAsync( new UnitEvent(id, UnitEvent.TypeCode, new UnitEvent.UnitEventData()) { Version = x })); await Task.WhenAll(tasks); var loader = buildClaptrapLifetimeScope.Resolve <IEventLoader>(); const int eventBeginVersion = Defaults.StateStartingVersion + 1; var eventEndVersion = eventBeginVersion + count; var events = await loader.GetEventsAsync(eventBeginVersion, eventEndVersion); var versions = events.Select(x => x.Version); logger.LogInformation("version from event loader : {version}", versions); versions.Should().BeInAscendingOrder() .And.OnlyHaveUniqueItems() .And.ContainInOrder(Enumerable.Range(Defaults.EventStartingVersion, count)); await OnStopHost(Host); await Host.StopAsync(); }
public async Task SaveStateOneClaptrapAsync(string accountId, int times) { using var lifetimeScope = BuildService().CreateScope(); var factory = (ClaptrapFactory)lifetimeScope.ServiceProvider.GetRequiredService <IClaptrapFactory>(); var id = new ClaptrapIdentity(accountId, Codes.Account); await using var buildClaptrapLifetimeScope = factory.BuildClaptrapLifetimeScope(id); var saver = buildClaptrapLifetimeScope.Resolve <IStateSaver>(); var states = Enumerable.Range(Defaults.StateStartingVersion, times) .Select(x => new UnitState { Data = UnitState.UnitStateData.Create(), Identity = id, Version = x }) .ToArray(); var tasks = states .Select(x => saver.SaveAsync(x)); await Task.WhenAll(tasks); var loader = buildClaptrapLifetimeScope.Resolve <IStateLoader>(); var state = await loader.GetStateSnapshotAsync(); Debug.Assert(state != null, nameof(state) + " != null"); state.Should().NotBeNull(); state.Version.Should().Be(times - 1); await OnStopHost(Host); await Host.StopAsync(); }
public async Task Success() { var container = CreateContainer(); await using var scope = container.BeginLifetimeScope(); var masterIdentity = new ClaptrapIdentity(Guid.NewGuid().ToString(), "TestCode"); await using var claptrap = scope.CreateSagaClaptrap(masterIdentity, "testFlow", typeof(TestFlowData)); var sagaFlow = SagaFlowBuilder.Create() .WithStep <TestStep1, CompensateStep1>() .WithStep <TestStep2, CompensateStep2>() .WithUserData(new TestFlowData()) .Build(); await claptrap.RunAsync(sagaFlow); var claptrapAccessor = scope.Resolve <IClaptrapAccessor>(); var claptrapStateData = (SagaStateData <TestFlowData>)claptrapAccessor.Claptrap.State.Data; claptrapStateData.SagaFlowState.IsCompleted.Should().BeTrue(); var flowData = (TestFlowData)claptrapStateData.GetUserData(); flowData.Test1.Should().BeTrue(); flowData.Test2.Should().BeTrue(); // there will be nothing change since flow completed. await claptrap.RunAsync(sagaFlow); }
private async Task MigrateAsync() { var id = new ClaptrapIdentity("1", Codes.Account); await using var scope = _claptrapFactory.BuildClaptrapLifetimeScope(id); var eventSaverMigration = scope.Resolve <IEventSaverMigration>(); await eventSaverMigration.MigrateAsync(); }
public async Task MultipleSent(int count) { var minionLocator = new TestMinionLocator(); using var host = QuickSetupTestHelper.BuildHost( DatabaseType.SQLite, RelationLocatorStrategy.SharedTable, AppsettingsFilenames, builder => { builder.RegisterInstance(minionLocator) .As <IMinionLocator>() .SingleInstance(); }, builder => builder.UseRabbitMQ(rabbitmq => rabbitmq.AsEventCenter()) ); var container = host.Services; var subscriberManager = container.GetRequiredService <IMQSubscriberManager>(); await subscriberManager.StartAsync(); var claptrapFactory = (ClaptrapFactory)container.GetRequiredService <IClaptrapFactory>(); var id = new ClaptrapIdentity("1", Codes.Account); await using var scope = claptrapFactory.BuildClaptrapLifetimeScope(id); var eventCenter = scope.Resolve <IEventCenter>(); var task = Enumerable.Range(0, count) .ToObservable() .Select(version => { var unitEvent = UnitEvent.Create(id); unitEvent.Version = version; return(unitEvent); }) .Select(e => Observable.FromAsync(() => eventCenter.SendToMinionsAsync(id, e))) .Merge(100) .ToTask(); await task; await Task.Delay(TimeSpan.FromSeconds(5)); await subscriberManager.CloseAsync(); await container.GetRequiredService <IMQSenderManager>().CloseAsync(); await host.StopAsync(); var receivedItems = minionLocator.Queue.ToArray(); var itemGroup = receivedItems .GroupBy(x => x.Identity); foreach (var grouping in itemGroup) { grouping .Select(x => x.Event.Version) .Should() .BeEquivalentTo(Enumerable.Range(0, count)); } }
public IEnumerable <IClaptrapMinionModule> GetClaptrapMinionModules(IClaptrapIdentity identity) { var claptrapDesign = _claptrapDesignStore.FindDesign(identity); var masterIdentity = new ClaptrapIdentity(identity.Id, claptrapDesign.ClaptrapMasterDesign.ClaptrapTypeCode); var re = new ClaptrapMinionModule(claptrapDesign, masterIdentity, identity); yield return(re); }
public static AutoMock CreateAutoMock(this IClaptrapDesign claptrapDesign, string id, IStateData stateData, Action <ContainerBuilder, ActorHost>?builderAction = default, Func <AutoMock>?autoMockFunc = default) { var claptrapIdentity = new ClaptrapIdentity(id, claptrapDesign.ClaptrapTypeCode); var actorTypeInformation = ActorTypeInformation.Get(claptrapDesign.ClaptrapBoxImplementationType); var actorHost = new ActorHost(actorTypeInformation, new ActorId(id),
public async Task CustomFactory() { using var root = BuildService().CreateScope(); var factory = (ClaptrapFactory)root.ServiceProvider.GetRequiredService <IClaptrapFactory>(); var claptrapIdentity = new ClaptrapIdentity("testId", Codes.CustomFactoryClaptrap); await using var claptrapScope = factory.BuildClaptrapLifetimeScope(claptrapIdentity); // Configuration files do not override custom factories that use Attribute await claptrapScope.Resolve <IEventSaver>().SaveEventAsync(default !);
public async Task InitAsync() { _logger.LogInformation("Start to init async"); if (_options.Value.SetupLocalDatabase) { var databaseType = _options.Value.DatabaseType; await _dataBaseService.StartAsync(databaseType, 30); _logger.LogInformation("Database setup completed."); } var optionsValue = _options.Value; accounts = new IEventSaver[optionsValue.ActorCount]; _scopes = new ILifetimeScope[optionsValue.ActorCount]; var scopes = Enumerable.Range(0, optionsValue.ActorCount) .Select((i, x) => { var re = new { Scope = _claptrapFactory.BuildClaptrapLifetimeScope(new ClaptrapIdentity(x.ToString(), Codes.Account)), ClaptrapIdentity = new ClaptrapIdentity(x.ToString(), Codes.Account), }; _scopes[i] = re.Scope; return(re); }) .ToArray(); _logger.LogInformation("Scopes created."); for (var i = 0; i < optionsValue.ActorCount; i++) { accounts[i] = scopes[i].Scope.Resolve <IEventSaver>(); } _logger.LogInformation("Accounts created."); events = new UnitEvent[optionsValue.ActorCount]; for (var i = 0; i < optionsValue.ActorCount; i++) { events[i] = UnitEvent.Create(scopes[i].ClaptrapIdentity); } _logger.LogInformation("Events created."); versions = new int[optionsValue.ActorCount]; var id = new ClaptrapIdentity("1", Codes.Account); await using var scope = _claptrapFactory.BuildClaptrapLifetimeScope(id); var eventSaverMigration = scope.Resolve <IEventSaverMigration>(); await eventSaverMigration.MigrateAsync(); _logger.LogInformation("Database migration done."); }
public async Task Success(string id, int inventory) { using var mocker = AutoMock.GetStrict(); mocker.Mock <ISkuRepository>() .Setup(x => x.GetInitInventoryAsync(id)) .ReturnsAsync(inventory); var handler = mocker.Create <SkuStateInitHandler>(); var identity = new ClaptrapIdentity(id, ClaptrapCodes.SkuGrain); var data = (SkuState)await handler.Create(identity); data.Inventory.Should().Be(inventory); }
public async Task <IActionResult> GetState(int itemId = 1) { var id = new ClaptrapIdentity(itemId.ToString(), ClaptrapCodes.AuctionItemActor); var auctionItemActor = _actorProxyFactory.GetClaptrap <IAuctionItemActor>(id); var state = await auctionItemActor.GetStateAsync(); var result = new { state = state }; return(Ok(result)); }
public IEvent Deserialize(string source) { var jsonModel = JsonConvert.DeserializeObject <EventJsonModel>(source); var eventData = _eventDataStringSerializer.Deserialize(jsonModel.ClaptrapTypeCode, jsonModel.EventTypeCode, jsonModel.DataJson); var id = new ClaptrapIdentity(jsonModel.ClaptrapId, jsonModel.ClaptrapTypeCode); var re = new DataEvent(id, jsonModel.EventTypeCode, eventData) { Version = jsonModel.Version }; return(re); }
// [TestCase(1000, 10, false)] public async Task SaveEventAsync(int actorCount, int count, bool validateByLoader) { using var lifetimeScope = BuildService().CreateScope(); var logger = lifetimeScope.ServiceProvider.GetRequiredService <ILogger <QuickSetupTestBase> >(); var factory = (ClaptrapFactory)lifetimeScope.ServiceProvider.GetRequiredService <IClaptrapFactory>(); var showTimeIndex = actorCount / 10; showTimeIndex = showTimeIndex == 0 ? 1 : showTimeIndex; var round = 1; var tasks = Enumerable.Range(0, actorCount) .Select(async actorId => { var index = Interlocked.Increment(ref round); var accountId = $"acc_{actorId}_{actorCount}_{count}_{index}"; var id = new ClaptrapIdentity(accountId, Codes.Account); await using var scope = factory.BuildClaptrapLifetimeScope(id); var saver = scope.Resolve <IEventSaver>(); var sourceEvent = UnitEvent.Create(id); var unitEvents = Enumerable.Range(Defaults.EventStartingVersion, count) .Select(x => sourceEvent with { Version = x }) .ToArray(); var sw = Stopwatch.StartNew(); foreach (var unitEvent in unitEvents) { await saver.SaveEventAsync(unitEvent); } sw.Stop(); if (actorId / showTimeIndex == 0) { Console.WriteLine($"cost {sw.ElapsedMilliseconds} ms to save event"); } if (validateByLoader) { var loader = scope.Resolve <IEventLoader>(); const int eventBeginVersion = Defaults.StateStartingVersion + 1; var eventEndVersion = eventBeginVersion + count; var events = await loader.GetEventsAsync(eventBeginVersion, eventEndVersion); var versions = events.Select(x => x.Version); logger.LogInformation("version from event loader : {version}", versions); versions.Should().BeInAscendingOrder() .And.OnlyHaveUniqueItems() .And.ContainInOrder(Enumerable.Range(Defaults.EventStartingVersion, count)); } });
public async Task <IActionResult> TryBidding([FromBody] TryBiddingWebApiInput webApiInput) { var input = new TryBiddingInput { Price = webApiInput.Price, UserId = webApiInput.UserId, }; var itemId = webApiInput.ItemId; var id = new ClaptrapIdentity(itemId.ToString(), ClaptrapCodes.AuctionItemActor); var auctionItemActor = _actorProxyFactory.GetClaptrap <IAuctionItemActor>(id); var result = await auctionItemActor.TryBidding(input); return(Ok(result)); }
public Task Failed() { using var mocker = AutoMock.GetStrict(); const string skuId = "yueluo-666"; mocker.Mock <ISkuRepository>() .Setup(x => x.GetInitInventoryAsync(skuId)) .Throws <BizException>(); var handler = mocker.Create <SkuStateInitHandler>(); var identity = new ClaptrapIdentity(skuId, ClaptrapCodes.SkuGrain); Assert.ThrowsAsync <BizException>(() => handler.Create(identity)); return(Task.CompletedTask); }
public async Task HandleEventAsync() { decimal oldBalance; decimal nowBalance; const decimal diff = 100M; const int times = 10; const string testId = "testId"; using (var lifetimeScope = BuildService().CreateScope()) { var factory = lifetimeScope.ServiceProvider.GetRequiredService <Account.Factory>(); var claptrapIdentity = new ClaptrapIdentity(testId, Codes.Account); IAccount account = factory.Invoke(claptrapIdentity); await account.ActivateAsync(); oldBalance = await account.GetBalanceAsync(); await Task.WhenAll(Enumerable.Range(0, times) .Select(i => account.ChangeBalanceAsync(diff))); var balance = await account.GetBalanceAsync(); await account.DeactivateAsync(); nowBalance = oldBalance + times * 100; balance.Should().Be(nowBalance); } Console.WriteLine($"balance change: {oldBalance} + {diff} = {nowBalance}"); using (var lifetimeScope = BuildService().CreateScope()) { var factory = lifetimeScope.ServiceProvider.GetService <AccountBalanceMinion.Factory>(); var claptrapIdentity = new ClaptrapIdentity(testId, Codes.AccountBalanceMinion); IAccountBalanceMinion accountBalance = factory.Invoke(claptrapIdentity); await accountBalance.ActivateAsync(); var balance = await accountBalance.GetBalanceAsync(); balance.Should().Be(nowBalance); Console.WriteLine($"balance from minion {balance}"); } await OnStopHost(Host); await Host.StopAsync(); }
public async Task Success() { using var mocker = AutoMock.GetStrict(); const string userId = "userId"; var stateData = new OrderState { OrderCreated = false }; var identity = new ClaptrapIdentity("666", ClaptrapCodes.OrderGrain); var createOrderInput = new CreateOrderInput { CartId = identity.Id, UserId = userId }; const string skuId = "yueluo-666"; const int skuCountInCart = 666; var cartItems = new Dictionary <string, int> { { skuId, skuCountInCart } }; mocker.MockStateData(stateData); mocker.MockStateIdentity(identity); var cartGrain = new Mock <ICartGrain>(); cartGrain.Setup(x => x.GetItemsAsync()) .ReturnsAsync(cartItems); cartGrain.Setup(x => x.RemoveAllItemsAsync()) .Returns(Task.CompletedTask); mocker.MockGrain(createOrderInput.CartId, cartGrain.Object); var skuGrain = new Mock <ISkuGrain>(); skuGrain.Setup(x => x.UpdateInventoryAsync(skuCountInCart)) .ReturnsAsync(0); mocker.MockGrain(skuId, skuGrain.Object); mocker.MockerEventCode <OrderCreatedEvent>(ClaptrapCodes.OrderCreated); mocker.Mock <IClaptrapGrainCommonService>() .Setup(x => x.ClaptrapAccessor.Claptrap.HandleEventAsync(It.IsAny <IEvent>())) .Returns(Task.CompletedTask); var handler = mocker.Create <OrderGrain>(); await handler.CreateOrderAsync(createOrderInput); }
public async Task HandleAsync(HttpContext context) { var sr = new StreamReader(context.Request.Body); var body = await sr.ReadToEndAsync(); var e = _eventStringSerializer.Deserialize(body); var jsonModel = _eventSerializer.Serialize(e); var minionTypeCode = _minionTypeCodes[e.ClaptrapIdentity.TypeCode]; var tasks = minionTypeCode.Select(async x => { var minionId = new ClaptrapIdentity(e.ClaptrapIdentity.Id, x); var actorProxy = _actorProxyFactory.Create(new ActorId(minionId.Id), minionId.TypeCode); await actorProxy.InvokeMethodAsync(nameof(IClaptrapMinionActor.MasterEventReceivedJsonAsync), new[] { jsonModel }); }); await Task.WhenAll(tasks); }
private async Task AsyncEventingBasicConsumerOnReceived(object sender, BasicDeliverEventArgs args, IClaptrapDesign minionDesign) { _logger.LogDebug("message received from rabbit mq, exchange : {exchange} ,routeKey : {routeKey}", args.Exchange, args.RoutingKey); var consumer = (IAsyncBasicConsumer)sender; consumer.Model.BasicAck(args.DeliveryTag, false); var payload = Decompress(args); var data = _messageSerializer.Deserialize(payload); var evt = _eventStringSerializer.Deserialize(data); var minionId = new ClaptrapIdentity(evt.ClaptrapIdentity.Id, minionDesign.ClaptrapTypeCode); var minionProxy = _minionLocator.CreateProxy(minionId); _logger.LogTrace("create minion proxy for {id}", minionId); await minionProxy.MasterEventReceivedAsync(new[] { evt }); _logger.LogDebug("a message sent to minion {minionId}", minionId); }
public Task AlreadyCreated() { using var mocker = AutoMock.GetStrict(); var stateData = new OrderState { OrderCreated = true }; mocker.MockStateData(stateData); var identity = new ClaptrapIdentity("666", ClaptrapCodes.OrderGrain); mocker.MockStateIdentity(identity); var handler = mocker.Create <OrderGrain>(); var createOrderInput = new CreateOrderInput { }; Assert.ThrowsAsync <BizException>(() => handler.CreateOrderAsync(createOrderInput)); return(Task.CompletedTask); }
private async Task RunCoreAsync() { await MigrateAsync(); var totalCount = _options.Value.TotalCount; var batchSize = _options.Value.BatchSize; var batchCount = totalCount / batchSize; var totalW = Stopwatch.StartNew(); var endSign = new int[_options.Value.WorkerCount]; var tcs = new TaskCompletionSource <int>(); var timeBag = new ConcurrentBag <List <long> >(); Parallel.For(0, _options.Value.WorkerCount, async workerId => { var id = new ClaptrapIdentity(workerId.ToString(), Codes.Account); await using var scope = _claptrapFactory.BuildClaptrapLifetimeScope(id); var saver = scope.Resolve <IEventEntitySaver <EventEntity> >(); var mapper = scope.Resolve <IEventEntityMapper <EventEntity> >(); var timeList = new List <long>(); var unitEvent = UnitEvent.Create(id); var entity = mapper.Map(unitEvent); for (var i = 0; i < batchCount; i++) { var versionStart = i * batchSize; var events = Enumerable.Range(versionStart, batchSize) .Select(version => entity with { Version = version }); var sw = Stopwatch.StartNew(); await saver.SaveManyAsync(events); sw.Stop(); timeList.Add(sw.ElapsedMilliseconds); _logger.LogTrace("batch {i} {percent:00.00}%: {total}", i, i * 1.0 / batchCount * 100, sw.Elapsed.Humanize(maxUnit: TimeUnit.Millisecond)); }
public async Task SaveStateMultipleClaptrapAsync(int claptrapCount) { const int stateVersion = 100; using var lifetimeScope = BuildService().CreateScope(); var logger = lifetimeScope.ServiceProvider.GetRequiredService <ILogger <QuickSetupTestBase> >(); var factory = (ClaptrapFactory)lifetimeScope.ServiceProvider.GetRequiredService <IClaptrapFactory>(); var sw = Stopwatch.StartNew(); var data = Enumerable.Range(0, claptrapCount) .Select(accountId => { var claptrapIdentity = new ClaptrapIdentity($"acc{accountId}", Codes.Account); return(new { id = claptrapIdentity, state = new UnitState { Data = UnitState.UnitStateData.Create(), Identity = claptrapIdentity, Version = stateVersion } }); }) .AsParallel() .ToArray(); sw.Stop(); logger.LogInformation("cost {time} ms to build data", sw.ElapsedMilliseconds); sw.Restart(); var lifetimes = data.Select(d => { var id = d.id; var buildClaptrapLifetimeScope = factory.BuildClaptrapLifetimeScope(id); return(new { id, d.state, lifetimeScope = buildClaptrapLifetimeScope, }); }) .ToArray(); sw.Stop(); logger.LogInformation("cost {time} ms to build lifetime", sw.ElapsedMilliseconds); sw.Restart(); var items = lifetimes.Select(d => { var id = d.id; var saver = d.lifetimeScope.Resolve <IStateSaver>(); return(new { id, d.state, saver, d.lifetimeScope, }); }) .ToArray(); sw.Stop(); logger.LogInformation("cost {time} ms to build items", sw.ElapsedMilliseconds); sw.Restart(); var tasks = items .Select(item => item.saver.SaveAsync(item.state)); await Task.WhenAll(tasks); sw.Stop(); logger.LogInformation("cost {time} ms to save items", sw.ElapsedMilliseconds); foreach (var item in items) { var loader = item.lifetimeScope.Resolve <IStateLoader>(); var state = await loader.GetStateSnapshotAsync(); Debug.Assert(state != null, nameof(state) + " != null"); state.Version.Should().Be(item.state.Version); } Parallel.ForEach(items, item => { item.lifetimeScope.Dispose(); }); await OnStopHost(Host); await Host.StopAsync(); }
public async Task Normal(CompressType compressType) { var random = new Random(); var minionLocator = new TestMinionLocator(); using var host = QuickSetupTestHelper.BuildHost( DatabaseType.SQLite, RelationLocatorStrategy.SharedTable, AppsettingsFilenames.Concat(new[] { $"configs/rabbitmq/appsettings.{compressType.ToString("G").ToLower()}.json" }), builder => { builder.RegisterInstance(minionLocator) .As <IMinionLocator>() .SingleInstance(); }, builder => builder.UseRabbitMQ(rabbitmq => rabbitmq.AsEventCenter()) ); var container = host.Services; var subscriberManager = container.GetRequiredService <IMQSubscriberManager>(); await subscriberManager.StartAsync(); var claptrapFactory = (ClaptrapFactory)container.GetRequiredService <IClaptrapFactory>(); var id1 = new ClaptrapIdentity("1", Codes.Account); await using var scope = claptrapFactory.BuildClaptrapLifetimeScope(id1); var eventCenter = scope.Resolve <IEventCenter>(); var eventData = new AccountBalanceChangeEvent { Diff = random.Next(0, 1000) }; var evt = new DataEvent(id1, Codes.AccountBalanceChangeEvent, eventData) { Version = 1 }; await eventCenter.SendToMinionsAsync(id1, evt); await Task.Delay(TimeSpan.FromSeconds(3)); minionLocator.Queue.Count.Should().Be(2); var dic = minionLocator.Queue.ToDictionary(x => x.Identity); var balanceMinionId = new ClaptrapIdentity(id1.Id, Codes.AccountBalanceMinion); var balanceMinionItem = dic[balanceMinionId]; AssertEvent(balanceMinionId, balanceMinionItem); var balanceHistoryMinionId = new ClaptrapIdentity(id1.Id, Codes.AccountBalanceMinion); var balanceHistoryMinionItem = dic[balanceHistoryMinionId]; AssertEvent(balanceHistoryMinionId, balanceHistoryMinionItem); await subscriberManager.CloseAsync(); await container.GetRequiredService <IMQSenderManager>().CloseAsync(); await host.StopAsync(); void AssertEvent(ClaptrapIdentity minionId, ReceivedItem item) { var(id, e) = item; id.Should().BeEquivalentTo(minionId); e.Version.Should().Be(evt.Version); e.EventTypeCode.Should().Be(evt.EventTypeCode); e.Data.Should().BeOfType <AccountBalanceChangeEvent>(); var data = (AccountBalanceChangeEvent)e.Data; data.Diff.Should().Be(eventData.Diff); } }