public async Task ItWorks() { var gotMessage = new ManualResetEvent(false); _activator.Handle <string>(async(bus, context, message) => { Console.WriteLine($"Got message with ID {context.Headers.GetValue(Headers.MessageId)} - waiting 2 minutes...."); await Task.Delay(TimeSpan.FromMinutes(2)); Console.WriteLine("done waiting"); gotMessage.Set(); }); _busStarter.Start(); await _bus.SendLocal("hej med dig min ven!"); gotMessage.WaitOrDie(TimeSpan.FromMinutes(2.1)); // shut down bus _bus.Dispose(); // see if queue is empty using var scope = new RebusTransactionScope(); var message = await _transport.Receive(scope.TransactionContext, CancellationToken.None); await scope.CompleteAsync(); if (message != null) { throw new AssertionException( $"Did not expect to receive a message - got one with ID {message.Headers.GetValue(Headers.MessageId)}"); } }
async Task <List <string> > GetAll(ITransport input) { var transportMessages = new List <string>(); var receivedNulls = 0; while (receivedNulls < 5) { using (var scope = new RebusTransactionScope()) { var msg = await input.Receive(scope.TransactionContext, _cancellationToken); if (msg != null) { transportMessages.Add(GetStringBody(msg)); await scope.CompleteAsync(); continue; } await Task.Delay(100); receivedNulls++; } } return(transportMessages); }
public static void UseRebusOutbox(this IApplicationBuilder app, string connectionString) { app.Use(async(context, next) => { // if you've set up DI resolution to fetch the current connection/transaction from a unit of work, you can do something like this: //var serviceProvider = context.RequestServices; //var connection = serviceProvider.GetRequiredService<SqlConnection>(); //var transaction = serviceProvider.GetRequiredService<SqlTransaction>(); // but in this case we'll work with a simulated unit of work here: await using var connection = new SqlConnection(connectionString); await connection.OpenAsync(); await using var transaction = connection.BeginTransaction(); using var scope = new RebusTransactionScope(); scope.UseOutbox(connection, transaction); // process the web request await next(); // insert outgoing messages await scope.CompleteAsync(); // commit! await transaction.CommitAsync(); }); }
public async Task ReceivesNonExpiredMessage() { var queueName = TestConfig.GetName("expiration"); var transport = _factory.Create(queueName); var id = Guid.NewGuid().ToString(); using (var scope = new RebusTransactionScope()) { var headers = new Dictionary <string, string> { { Headers.MessageId, Guid.NewGuid().ToString() }, { "recognizzle", id } }; await transport.Send(queueName, MessageWith(headers), scope.TransactionContext); await scope.CompleteAsync(); } await Task.Delay(5000); using (var scope = new RebusTransactionScope()) { var transportMessage = await transport.Receive(scope.TransactionContext, _cancellationToken); await scope.CompleteAsync(); Assert.That(transportMessage, Is.Not.Null); var headers = transportMessage.Headers; Assert.That(headers.ContainsKey("recognizzle")); Assert.That(headers["recognizzle"], Is.EqualTo(id)); } }
public static async Task <TransportMessage> AwaitReceive(this ITransport transport, double timeoutSeconds = 5) { var stopwatch = Stopwatch.StartNew(); var timeout = TimeSpan.FromSeconds(timeoutSeconds); var source = new CancellationTokenSource(); while (stopwatch.Elapsed < timeout) { TransportMessage receivedTransportMessage; using (var scope = new RebusTransactionScope()) { receivedTransportMessage = await transport.Receive(scope.TransactionContext, source.Token); await scope.CompleteAsync(); } if (receivedTransportMessage != null) { return(receivedTransportMessage); } } throw new AssertionException($"Did not receive transport message from {transport} within {timeout} timeout"); }
public async Task ReceivesAlmostExpiredMessage() { var queueName = TestConfig.GetName("expiration"); var transport = _factory.Create(queueName); var id = Guid.NewGuid().ToString(); using (var scope = new RebusTransactionScope()) { var headers = new Dictionary <string, string> { { Headers.MessageId, Guid.NewGuid().ToString() }, { "recognizzle", id }, { Headers.TimeToBeReceived, "00:00:20" }, { Headers.SentTime, DateTimeOffset.UtcNow.ToString("O") }//< expires after 10 seconds! }; await transport.Send(queueName, MessageWith(headers), scope.TransactionContext); await scope.CompleteAsync(); } await Task.Delay(3000); using (var scope = new RebusTransactionScope()) { var transportMessage = await transport.Receive(scope.TransactionContext, _cancellationToken); await scope.CompleteAsync(); Assert.That(transportMessage, Is.Not.Null); } }
public static IEnumerable <TransportMessage> GetMessages(this SqlServerTransport transport) { var messages = new List <TransportMessage>(); AsyncHelpers.RunSync(async() => { while (true) { using (var scope = new RebusTransactionScope()) { var transportMessage = await transport.Receive(scope.TransactionContext, CancellationToken.None); if (transportMessage == null) { break; } messages.Add(transportMessage); await scope.CompleteAsync(); } } }); return(messages); }
public static async Task <TransportMessage> WaitForNextMessage(this ITransport transport, int timeoutSeconds = 5) { var stopwatch = Stopwatch.StartNew(); while (true) { using (var scope = new RebusTransactionScope()) { var nextMessage = await transport.Receive(scope.TransactionContext, CancellationToken.None); await scope.CompleteAsync(); if (nextMessage != null) { return(nextMessage); } } await Task.Delay(100); if (stopwatch.Elapsed < TimeSpan.FromSeconds(timeoutSeconds)) { continue; } throw new TimeoutException($"Did not receive message from transport with address '{transport.Address}' within {timeoutSeconds} s timeout"); } }
static async Task PutInQueue(ITransport transport, TransportMessage transportMessage) { using var scope = new RebusTransactionScope(); await transport.Send(QueueName, transportMessage, scope.TransactionContext); await scope.CompleteAsync(); }
public async Task Send_StoresMessagesToOutboxOnCommit() { using var rebusTransactionScope = new RebusTransactionScope(); var transportMessage1 = new TransportMessage(new Dictionary <string, string>(), new byte[0]); const string destinationAddress1 = "TestAddress1"; var transportMessage2 = new TransportMessage(new Dictionary <string, string>(), new byte[0]); const string destinationAddress2 = "TestAddress2"; await _decorator.Send(destinationAddress1, transportMessage1, rebusTransactionScope.TransactionContext); await _decorator.Send(destinationAddress2, transportMessage2, rebusTransactionScope.TransactionContext); Assert.True(rebusTransactionScope.TransactionContext.Items.TryGetValue( OutboxTransportDecorator.OutgoingMessagesItemsKey, out var outgoingMessagesObject)); var outgoingMessages = ((IEnumerable <TransportMessage>)outgoingMessagesObject).ToArray(); Assert.Contains(transportMessage1, outgoingMessages); Assert.Contains(transportMessage2, outgoingMessages); var recipient1 = Assert.Contains(OutboxHeaders.Recipient, transportMessage1.Headers as IDictionary <string, string>); Assert.Equal(destinationAddress1, recipient1); var recipient2 = Assert.Contains(OutboxHeaders.Recipient, transportMessage2.Headers as IDictionary <string, string>); Assert.Equal(destinationAddress2, recipient2); await rebusTransactionScope.CompleteAsync(); await _outboxStorage.Received().Store(transportMessage1); await _outboxStorage.Received().Store(transportMessage2); }
public async Task CheckIt() { var activator = Using(new BuiltinHandlerActivator()); var network = new InMemNetwork(); var rolledBackMessageReceived = new ManualResetEvent(initialState: false); activator.Handle <ThisMessageShouldNotBeSent>(async _ => rolledBackMessageReceived.Set()); activator.Handle <string>(async(bus, context, message) => { using (var scope = new RebusTransactionScope()) { await scope.CompleteAsync(); } await bus.SendLocal(new ThisMessageShouldNotBeSent()); throw new InvalidOperationException("OH NO!"); }); Configure.With(activator) .Transport(t => t.UseInMemoryTransport(network, "queue-name")) .Options(o => o.FailFastOn <InvalidOperationException>(when: exception => exception.Message.Contains("OH NO!"))) .Start(); await activator.Bus.SendLocal("HEJ MED DIG MIN VEN"); Assert.That(rolledBackMessageReceived.WaitOne(TimeSpan.FromSeconds(3)), Is.False, "Did not expect to receive the ThisMessageShouldNotBeSent, because its Rebus handler transaction was rolled back by an exception"); }
public async Task CannotReceiveSameMessageTwiceEvenWhenSnapahotIsolationIsOn() { const string sentText = "HEJ MED DIG MIN VEN!!!!!11"; var transportMessage = new TransportMessage(new Dictionary <string, string>(), Encoding.UTF8.GetBytes(sentText)); var transport1 = GetTransport(";MultipleActiveResultSets=True;" + SqlTestHelper.ConnectionString, IsolationLevel.Snapshot); var transport2 = GetTransport(SqlTestHelper.ConnectionString, IsolationLevel.Snapshot); using (var scope = new RebusTransactionScope()) { await transport1.Send(_queueName, transportMessage, scope.TransactionContext); await scope.CompleteAsync(); } using (var scope1 = new RebusTransactionScope()) using (var scope2 = new RebusTransactionScope()) { var message1 = await transport1.Receive(scope1.TransactionContext, CancellationToken.None); var message2 = await transport2.Receive(scope2.TransactionContext, CancellationToken.None); Assert.That(message1, Is.Not.Null); Assert.That(Encoding.UTF8.GetString(message1.Body), Is.EqualTo(sentText)); Assert.That(message2, Is.Null, "Expected the second message to be null, because we should NOT be able to accidentally peek at the same message as another ongoing transaction"); await scope2.CompleteAsync(); await scope1.CompleteAsync(); } }
public async Task VeryBasicTransactionThing() { const string destinationQueueName = "another-queue"; var network = new InMemNetwork(); network.CreateQueue(destinationQueueName); var transport = new InMemTransport(network, "test-queue"); transport.Initialize(); using (var scope = new RebusTransactionScope()) { var headers = new Dictionary <string, string> { { Headers.MessageId, Guid.NewGuid().ToString() } }; await transport.Send( destinationAddress : destinationQueueName, message : new TransportMessage(headers, new byte[] { 1, 2, 3 }), context : scope.TransactionContext ); Assert.That(network.Count(destinationQueueName), Is.EqualTo(0), $"Expected ZERO messages in queue '{destinationQueueName}' at this point, because the scope was not completed"); await scope.CompleteAsync(); } Assert.That(network.Count(destinationQueueName), Is.EqualTo(1), $"Expected 1 message in queue '{destinationQueueName}' at this point, because the scope is completed now"); }
public async Task DoesNotReceiveExpiredMessage() { var queueName = TestConfig.GetName("expiration"); var transport = _factory.Create(queueName); var id = Guid.NewGuid().ToString(); using (var scope = new RebusTransactionScope()) { var headers = new Dictionary <string, string> { { Headers.MessageId, Guid.NewGuid().ToString() }, { "recognizzle", id }, { Headers.TimeToBeReceived, "00:00:04" } //< expires after 4 seconds! }; await transport.Send(queueName, MessageWith(headers), scope.TransactionContext); await scope.CompleteAsync(); } const int millisecondsDelay = 7000; var stopwatch = Stopwatch.StartNew(); await Task.Delay(millisecondsDelay); Console.WriteLine($"Delay of {millisecondsDelay} ms actually lasted {stopwatch.ElapsedMilliseconds:0} ms"); using (var scope = new RebusTransactionScope()) { var transportMessage = await transport.Receive(scope.TransactionContext, _cancellationToken); await scope.CompleteAsync(); Assert.That(transportMessage, Is.Null); } }
public async Task DoesNotHitTheLimit() { var queueName = TestConfig.GetName("payload-limit"); Using(new QueueDeleter(queueName)); var activator = Using(new BuiltinHandlerActivator()); activator.Handle <MessageWithText>(async _ => { }); var bus = Configure.With(activator) .Logging(l => l.Console(LogLevel.Info)) .Transport(t => t.UseAzureServiceBus(AsbTestConfig.ConnectionString, queueName)) .Start(); using (var scope = new RebusTransactionScope()) { var strings = Enumerable.Range(0, 1000) .Select(n => new MessageWithText($"message {n}")); await Task.WhenAll(strings.Select(str => bus.SendLocal(str))); await scope.CompleteAsync(); } }
public void WorksWithPrefetch(int prefetch, int numberOfMessages, int maxParallelism) { var activator = Using(new BuiltinHandlerActivator()); var counter = new SharedCounter(numberOfMessages); Using(counter); activator.Handle <string>(async str => { counter.Decrement(); }); Console.WriteLine("Sending {0} messages", numberOfMessages); var transport = GetTransport(); var tasks = Enumerable.Range(0, numberOfMessages) .Select(i => $"THIS IS MESSAGE # {i}") .Select(async msg => { using (var scope = new RebusTransactionScope()) { var headers = DefaultHeaders(); var body = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(msg)); var transportMessage = new TransportMessage(headers, body); await transport.Send(_queueName, transportMessage, scope.TransactionContext); await scope.CompleteAsync(); } }) .ToArray(); Task.WhenAll(tasks).Wait(); Console.WriteLine("Receiving {0} messages", numberOfMessages); var stopwatch = Stopwatch.StartNew(); Configure.With(activator) .Logging(l => l.Console(LogLevel.Info)) .Transport(t => { t.UseAzureServiceBus(AsbTestConfig.ConnectionString, _queueName) .EnablePrefetching(prefetch); }) .Options(o => { o.SetNumberOfWorkers(1); o.SetMaxParallelism(maxParallelism); }) .Start(); counter.WaitForResetEvent(timeoutSeconds: (int)(numberOfMessages * 0.1 + 3)); var elapsedSeconds = stopwatch.Elapsed.TotalSeconds; Console.WriteLine("Receiving {0} messages took {1:0.0} s - that's {2:0.0} msg/s", numberOfMessages, elapsedSeconds, numberOfMessages / elapsedSeconds); }
private async Task ProcessOutboxMessages() { _log.Debug("Starting outbox messages processor"); while (!_busDisposalCancellationToken.IsCancellationRequested) { try { bool waitForMessages; using (var transactionScope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled)) { var messages = await _outboxStorage.Retrieve(_busDisposalCancellationToken, _topMessagesToRetrieve); if (messages.Length > 0) { using (var rebusTransactionScope = new RebusTransactionScope()) { foreach (var message in messages) { var destinationAddress = message.Headers[OutboxHeaders.Recipient]; message.Headers.Remove(OutboxHeaders.Recipient); await _transport.Send(destinationAddress, message, rebusTransactionScope.TransactionContext); } await rebusTransactionScope.CompleteAsync(); } waitForMessages = false; } else { waitForMessages = true; } transactionScope.Complete(); } if (waitForMessages) { await _backoffStrategy.WaitNoMessageAsync(_busDisposalCancellationToken); } else { _backoffStrategy.Reset(); } } catch (OperationCanceledException) when(_busDisposalCancellationToken.IsCancellationRequested) { // we're shutting down } catch (Exception exception) { _log.Error(exception, "Unhandled exception in outbox messages processor"); await _backoffStrategy.WaitErrorAsync(_busDisposalCancellationToken); } } _log.Debug("Outbox messages processor stopped"); }
public async Task LotsOfAsyncStuffGoingDown(int numberOfMessages) { var receivedMessages = 0L; var messageIds = new ConcurrentDictionary <int, int>(); Console.WriteLine("Sending {0} messages", numberOfMessages); await Task.WhenAll(Enumerable.Range(0, numberOfMessages) .Select(async i => { using (var scope = new RebusTransactionScope()) { await _transport.Send(QueueName, RecognizableMessage(i), scope.TransactionContext); await scope.CompleteAsync(); messageIds[i] = 0; } })); Console.WriteLine("Receiving {0} messages", numberOfMessages); using (new Timer(_ => Console.WriteLine("Received: {0} msgs", receivedMessages), null, 0, 1000)) { var stopwatch = Stopwatch.StartNew(); while (Interlocked.Read(ref receivedMessages) < numberOfMessages && stopwatch.Elapsed < TimeSpan.FromMinutes(2)) { await Task.WhenAll(Enumerable.Range(0, 10).Select(async __ => { using (var scope = new RebusTransactionScope()) { var msg = await _transport.Receive(scope.TransactionContext, _cancellationToken); await scope.CompleteAsync(); if (msg != null) { Interlocked.Increment(ref receivedMessages); var id = int.Parse(msg.Headers["id"]); messageIds.AddOrUpdate(id, 1, (_, existing) => existing + 1); } } })); } await Task.Delay(3000); } Assert.That(messageIds.Keys.OrderBy(k => k).ToArray(), Is.EqualTo(Enumerable.Range(0, numberOfMessages).ToArray())); var kvpsDifferentThanOne = messageIds.Where(kvp => kvp.Value != 1).ToList(); if (kvpsDifferentThanOne.Any()) { Assert.Fail(@"Oh no! the following IDs were not received exactly once: {0}", string.Join(Environment.NewLine, kvpsDifferentThanOne.Select(kvp => $" {kvp.Key}: {kvp.Value}"))); } }
public async Task CommitSentMessageToStorage() { using (var scope = new RebusTransactionScope()) { await _transport.Send(QueueName, RecognizableMessage(), AmbientTransactionContext.Current); await scope.CompleteAsync(); } Assert.That(true, Is.True); }
async Task WithContext(Func <ITransactionContext, Task> contextAction, bool completeTransaction = true) { using (var scope = new RebusTransactionScope()) { await contextAction(scope.TransactionContext); if (completeTransaction) { await scope.CompleteAsync(); } } }
static async Task SendMessageTo(string queueName) { using (var transport = new MsmqTransport(queueName, new ConsoleLoggerFactory(false))) { using (var scope = new RebusTransactionScope()) { var transportMessage = new TransportMessage(new Dictionary <string, string>(), new byte[0]); await transport.Send(queueName, transportMessage, scope.TransactionContext); await scope.CompleteAsync(); } } }
private async Task _processOutboxMessages(CancellationToken ctk) { _log.Debug("Starting outbox messages processor"); while (!ctk.IsCancellationRequested) { try { bool waitForMessages = true; using (var ctx = _outboxContextFactory.Create()) { var messages = await ctx.PeekLockMessagesAsync(_topMessagesToRetrieve, ctk); if (messages.Any()) { using (var rebusTransactionScope = new RebusTransactionScope()) { foreach (var message in messages) { var destinationAddress = message.Headers[OutboxTransportDecorator._outboxRecepientHeader]; message.Headers.Remove(OutboxTransportDecorator._outboxRecepientHeader); await _transport.Send(destinationAddress, new TransportMessage(message.Headers, message.Body), rebusTransactionScope.TransactionContext).WithCancellation(ctk); } await rebusTransactionScope.CompleteAsync().WithCancellation(ctk); } waitForMessages = false; _backoffStrategy.Reset(); } ctx.Commit(); } if (waitForMessages) { await _backoffStrategy.WaitNoMessageAsync(ctk); } } catch (OperationCanceledException) when(ctk.IsCancellationRequested) { // we're shutting down } catch (Exception exception) { _log.Error(exception, "Unhandled exception in outbox messages processor"); await _backoffStrategy.WaitErrorAsync(ctk); } } _log.Debug("Outbox messages processor stopped"); }
public async override Task PublishManyFromOutboxAsync(IEnumerable <OutgoingEventInfo> outgoingEvents, OutboxConfig outboxConfig) { var outgoingEventArray = outgoingEvents.ToArray(); using (var scope = new RebusTransactionScope()) { foreach (var outgoingEvent in outgoingEventArray) { await PublishFromOutboxAsync(outgoingEvent, outboxConfig); } await scope.CompleteAsync(); } }
public async Task ItWorks(int messageCount) { using (var scope = new RebusTransactionScope()) { var context = scope.TransactionContext; messageCount.Times(() => _transport.Send(_inputQueueAddress, MessageWith("message-1"), context).Wait()); await scope.CompleteAsync(); } var receivedMessages = await _transport.ReceiveAll(); Assert.That(receivedMessages.Count, Is.EqualTo(messageCount)); }
private async Task <Unit> ProgressMessage(string message) { using (var scope = new RebusTransactionScope()) { await _bus.Send(new ConvergeVirtualMachineProgressEvent { OperationId = _operationId, Message = message }).ConfigureAwait(false); // commit it like this await scope.CompleteAsync().ConfigureAwait(false); } return(Unit.Default); }
public async Task IgnoresMessagesWithSameOrderingKeyAsLeasedMessages() { using (var scope = new RebusTransactionScope()) { // Send three messages, the first two using the same ordering key, one without an ordering key // and the last one with a different key const string orderingKey = "ordering-key"; const string differentOrderingKey = "differentOrderingKey"; await _transport.Send(QueueName, RecognizableMessage(1, orderingKey), scope.TransactionContext); await _transport.Send(QueueName, RecognizableMessage(2, orderingKey), scope.TransactionContext); await _transport.Send(QueueName, RecognizableMessage(3), scope.TransactionContext); await _transport.Send(QueueName, RecognizableMessage(4, differentOrderingKey), scope.TransactionContext); await scope.CompleteAsync(); } // We should get message 1, skip 2, then 3 and 4 while inside the transaction using (var scope = new RebusTransactionScope()) { var transportMessage1 = await _transport.Receive(scope.TransactionContext, _cancellationToken); var transportMessage2 = await _transport.Receive(scope.TransactionContext, _cancellationToken); var transportMessage3 = await _transport.Receive(scope.TransactionContext, _cancellationToken); var transportMessage4 = await _transport.Receive(scope.TransactionContext, _cancellationToken); await scope.CompleteAsync(); AssertMessageIsRecognized(transportMessage1, 1); AssertMessageIsRecognized(transportMessage2, 3); AssertMessageIsRecognized(transportMessage3, 4); Assert.IsNull(transportMessage4); } // Now that message one is completed, we should then receive message 2 using (var scope = new RebusTransactionScope()) { var transportMessage = await _transport.Receive(scope.TransactionContext, _cancellationToken); await scope.CompleteAsync(); AssertMessageIsRecognized(transportMessage, 2); } }
static async Task <string> ReceiveMessageBody(ITransport transport) { using var scope = new RebusTransactionScope(); var transportMessage = await transport.Receive(scope.TransactionContext, CancellationToken.None); if (transportMessage == null) { return(null); } var body = Encoding.UTF8.GetString(transportMessage.Body); await scope.CompleteAsync(); return(body); }
private async Task PublishMessage(TelegramMessage message) { var esbmessage = new BotMessage() { MessageId = message.MessageId.ToString(), BotUserId = message.Chat.Id.ToString(), Text = message.Text, SendDate = message.Date.Ticks }; using (var scope = new RebusTransactionScope()) { await _activator.Bus.SendLocal(esbmessage).ConfigureAwait(false); await scope.CompleteAsync().ConfigureAwait(false); } }
private async Task <Unit> ProgressMessage(string message) { using (var scope = new RebusTransactionScope()) { await _bus.Publish(new OperationTaskProgressEvent { Id = Guid.NewGuid(), OperationId = _operationId, TaskId = _taskId, Message = message, Timestamp = DateTimeOffset.UtcNow, }).ConfigureAwait(false); // commit it like this await scope.CompleteAsync().ConfigureAwait(false); } return(Unit.Default); }
public async Task ReceivesSentMessageWhenTransactionIsCommitted() { using (var scope = new RebusTransactionScope()) { await _transport.Send(QueueName, RecognizableMessage(), scope.TransactionContext); await scope.CompleteAsync(); } using (var scope = new RebusTransactionScope()) { var transportMessage = await _transport.Receive(scope.TransactionContext, _cancellationToken); await scope.CompleteAsync(); AssertMessageIsRecognized(transportMessage); } }