public async Task CanHandleMessageAndSendOutgoingMessagesEvenWhenTransportIsFlaky() { using var gotSomeMessage = new ManualResetEvent(initialState: false); using var gotAnotherMessage = new ManualResetEvent(initialState: false); var flakySenderTransportDecoratorSettings = new FlakySenderTransportDecoratorSettings(); async Task HandlerFunction(IBus bus, IMessageContext context, SomeMessage message) { await bus.Advanced.Routing.Send("secondConsumer", new AnotherMessage()); gotSomeMessage.Set(); } using var firstConsumer = CreateConsumer("firstConsumer", activator => activator.Handle <SomeMessage>(HandlerFunction), flakySenderTransportDecoratorSettings); using var secondConsumer = CreateConsumer("secondConsumer", activator => activator.Handle <AnotherMessage>(async _ => gotAnotherMessage.Set())); using var client = CreateOneWayClient(router => router.TypeBased().Map <SomeMessage>("firstConsumer")); // make it so that the first consumer cannot send flakySenderTransportDecoratorSettings.SuccessRate = 0; await client.Send(new SomeMessage()); // wait for SomeMessage to be handled gotSomeMessage.WaitOrDie(timeout: TimeSpan.FromSeconds(3)); // now make it possible for first consumer to send again flakySenderTransportDecoratorSettings.SuccessRate = 1; // wait for AnotherMessage to arrive gotAnotherMessage.WaitOrDie(timeout: TimeSpan.FromSeconds(15)); }
IBus CreateOneWayClient(Action <StandardConfigurer <IRouter> > routing = null, FlakySenderTransportDecoratorSettings flakySenderTransportDecoratorSettings = null) { return(Configure.With(new BuiltinHandlerActivator()) .Transport(t => { t.UseInMemoryTransportAsOneWayClient(_network); if (flakySenderTransportDecoratorSettings != null) { t.Decorate(c => new FlakySenderTransportDecorator(c.Get <ITransport>(), flakySenderTransportDecoratorSettings)); } }) .Routing(r => routing?.Invoke(r)) .Subscriptions(s => s.StoreInMemory(_subscriberStore)) .Outbox(o => o.StoreInSqlServer(ConnectionString, "RebusOutbox")) .Start()); }
public async Task CanUseOutboxOutsideOfRebusHandler_Publish(bool commitTransaction, bool expectMessageToBeReceived) { var settings = new FlakySenderTransportDecoratorSettings(); using var messageWasReceived = new ManualResetEvent(initialState: false); using var server = CreateConsumer("server", a => a.Handle <SomeMessage>(async _ => messageWasReceived.Set())); await server.Subscribe <SomeMessage>(); using var client = CreateOneWayClient(flakySenderTransportDecoratorSettings: settings); // set success rate pretty low, so we're sure that it's currently not possible to use the // real transport - this is a job for the outbox! settings.SuccessRate = 0; // pretending we're in a web app - we have these two bad boys at work: await using (var connection = new SqlConnection(ConnectionString)) { await connection.OpenAsync(); await using var transaction = connection.BeginTransaction(); // this is how we would use the outbox for outgoing messages using var scope = new RebusTransactionScope(); scope.UseOutbox(connection, transaction); await client.Publish(new SomeMessage()); await scope.CompleteAsync(); if (commitTransaction) { // this is what we were all waiting for! await transaction.CommitAsync(); } } // we would not have gotten this far without the outbox - now let's pretend that the transport has recovered settings.SuccessRate = 1; // wait for server to receive the event Assert.That(messageWasReceived.WaitOne(TimeSpan.FromSeconds(15)), Is.EqualTo(expectMessageToBeReceived), $"When commitTransaction={commitTransaction} we {(expectMessageToBeReceived ? "expected the message to be sent and thus received" : "did NOT expect the message to be sent and therefore also not received")}"); }
IBus CreateConsumer(string queueName, Action <BuiltinHandlerActivator> handlers = null, FlakySenderTransportDecoratorSettings flakySenderTransportDecoratorSettings = null) { var activator = new BuiltinHandlerActivator(); handlers?.Invoke(activator); Configure.With(activator) .Transport(t => { t.UseInMemoryTransport(_network, queueName); if (flakySenderTransportDecoratorSettings != null) { t.Decorate(c => new FlakySenderTransportDecorator(c.Get <ITransport>(), flakySenderTransportDecoratorSettings)); } }) .Subscriptions(s => s.StoreInMemory(_subscriberStore)) .Outbox(o => o.StoreInSqlServer(ConnectionString, "RebusOutbox")) .Start(); return(activator.Bus); }
public FlakySenderTransportDecorator(ITransport transport, FlakySenderTransportDecoratorSettings flakySenderTransportDecoratorSettings) { _transport = transport; _flakySenderTransportDecoratorSettings = flakySenderTransportDecoratorSettings; }