public async Task Should_reset_delivery_counter(TransportTransactionMode transactionMode) { var sentDelayedMessage = CreateTaskCompletionSource <ErrorContext>(); var sendingDelayedMessage = false; await StartPump( (_, __) => throw new Exception("Simulated exception"), async (context, _) => { if (!sendingDelayedMessage) { sendingDelayedMessage = true; await SendMessage(InputQueueName, context.Message.Headers, context.TransportTransaction); } else { sentDelayedMessage.SetResult(context); } return(ErrorHandleResult.Handled); }, transactionMode); await SendMessage(InputQueueName); var errorContext = await sentDelayedMessage.Task; Assert.AreEqual(1, errorContext.ImmediateProcessingFailures, "Should track delivery attempts between immediate retries"); }
public async Task Should_dispatch_the_message(TransportTransactionMode transactionMode) { var messageReceived = new TaskCompletionSource<bool>(); OnTestTimeout(() => messageReceived.SetResult(false)); await StartPump( context => { if (context.Headers.ContainsKey("FromOnError")) { messageReceived.SetResult(true); return Task.FromResult(0); } throw new Exception("Simulated exception"); }, async context => { await SendMessage(InputQueueName, new Dictionary<string, string> { { "FromOnError", "true" } }, context.TransportTransaction); return ErrorHandleResult.Handled; }, transactionMode); await SendMessage(InputQueueName); Assert.True(await messageReceived.Task, "Message not dispatched properly"); }
public async Task Should_call_on_error(TransportTransactionMode transactionMode) { var onErrorCalled = new TaskCompletionSource <ErrorContext>(); OnTestTimeout(() => onErrorCalled.SetCanceled()); await StartPump(context => { throw new Exception("Simulated exception"); }, context => { onErrorCalled.SetResult(context); return(Task.FromResult(ErrorHandleResult.Handled)); }, transactionMode); await SendMessage(InputQueueName, new Dictionary <string, string> { { "MyHeader", "MyValue" } }); var errorContext = await onErrorCalled.Task; Assert.AreEqual(errorContext.Exception.Message, "Simulated exception", "Should preserve the exception"); Assert.AreEqual(1, errorContext.ImmediateProcessingFailures, "Should track the number of delivery attempts"); Assert.AreEqual("MyValue", errorContext.Message.Headers["MyHeader"], "Should pass the message headers"); }
public async Task Should_retry_immediately(TransportTransactionMode transactionMode) { var messageRedelivered = new TaskCompletionSource<bool>(); OnTestTimeout(() => messageRedelivered.SetResult(false)); var hasBeenCalled = false; var onErrorCalled = false; await StartPump( context => { if (hasBeenCalled) { messageRedelivered.SetResult(true); return Task.FromResult(0); } hasBeenCalled = true; context.ReceiveCancellationTokenSource.Cancel(); return Task.FromResult(0); }, context => { onErrorCalled = true; return Task.FromResult(ErrorHandleResult.RetryRequired); }, transactionMode); await SendMessage(InputQueueName); Assert.True(await messageRedelivered.Task, "Should redeliver message"); Assert.False(onErrorCalled, "Abort should not invoke on error"); }
public async Task Should_call_on_error(TransportTransactionMode transactionMode) { var onErrorCalled = new TaskCompletionSource<ErrorContext>(); OnTestTimeout(() => onErrorCalled.SetCanceled()); await StartPump(context => { throw new Exception("Simulated exception"); }, context => { onErrorCalled.SetResult(context); return Task.FromResult(ErrorHandleResult.Handled); }, transactionMode); await SendMessage(InputQueueName, new Dictionary<string, string> { { "MyHeader", "MyValue" } }); var errorContext = await onErrorCalled.Task; Assert.AreEqual(errorContext.Exception.Message, "Simulated exception", "Should preserve the exception"); Assert.AreEqual(1, errorContext.ImmediateProcessingFailures, "Should track the number of delivery attempts"); Assert.AreEqual("MyValue", errorContext.Message.Headers["MyHeader"], "Should pass the message headers"); }
public async Task Should_retry_immediately(TransportTransactionMode transactionMode) { var messageRetried = new TaskCompletionSource<bool>(); OnTestTimeout(() => messageRetried.SetResult(false)); var hasBeenCalled = false; await StartPump( context => { if (hasBeenCalled) { messageRetried.SetResult(true); return Task.FromResult(0); } hasBeenCalled = true; throw new Exception("Simulated exception"); }, context => Task.FromResult(ErrorHandleResult.RetryRequired), transactionMode); await SendMessage(InputQueueName); Assert.True(await messageRetried.Task, "Should retry if asked so"); }
public async Task Write(TransportTransactionMode transactionMode) { var endpointConfiguration = EndpointConfigBuilder.BuildEndpoint(nameof(MsmqTransportIntegrationTests)); var typesToScan = TypeScanner.NestedTypes <MsmqTransportIntegrationTests>(); endpointConfiguration.SetTypesToScan(typesToScan); var transport = endpointConfiguration.UseTransport <MsmqTransport>(); transport.Transactions(transactionMode); var persistence = endpointConfiguration.UsePersistence <SqlPersistence>(); persistence.ConnectionBuilder(MsSqlConnectionBuilder.Build); persistence.DisableInstaller(); persistence.SubscriptionSettings().DisableCache(); var endpoint = await Endpoint.Start(endpointConfiguration).ConfigureAwait(false); var startSagaMessage = new StartSagaMessage { StartId = Guid.NewGuid() }; await endpoint.SendLocal(startSagaMessage).ConfigureAwait(false); ManualResetEvent.WaitOne(); await endpoint.Stop().ConfigureAwait(false); }
public async Task Should_complete(TransportTransactionMode transactionMode) { CancellationToken onErrorToken = default; var onErrorStarted = CreateTaskCompletionSource(); var pumpStopping = CreateTaskCompletionSource(); await StartPump( (_, __) => throw new Exception(), async (_, cancellationToken) => { onErrorStarted.SetResult(); await pumpStopping.Task; onErrorToken = cancellationToken; return(ErrorHandleResult.Handled); }, transactionMode); await SendMessage(InputQueueName); await onErrorStarted.Task; var pumpTask = StopPump(); pumpStopping.SetResult(); await pumpTask; Assert.False(onErrorToken.IsCancellationRequested); }
public async Task Should_roll_back(TransportTransactionMode transactionMode) { var errorHandled = CreateTaskCompletionSource <ErrorContext>(); await StartPump( (context, _) => { context.Headers["test-header"] = "modified"; throw new Exception(); }, (context, __) => { errorHandled.SetResult(context); return(Task.FromResult(ErrorHandleResult.Handled)); }, transactionMode); await SendMessage(InputQueueName, new Dictionary <string, string> { { "test-header", "original" } }); var errorContext = await errorHandled.Task; Assert.AreEqual("original", errorContext.Message.Headers["test-header"]); }
public TransportConfigurationResult Configure(SettingsHolder settings, TransportTransactionMode transactionMode) { settings.Set("Transport.ConnectionString", Environment.GetEnvironmentVariable("AzureServiceBus.ConnectionString")); var connectionString = settings.Get <string>("Transport.ConnectionString"); settings.Set <Conventions>(new Conventions()); settings.Set(WellKnownConfigurationKeys.Core.MainSerializerSettingsKey, Tuple.Create <SerializationDefinition, SettingsHolder>(new XmlSerializer(), settings)); settings.Set("NServiceBus.SharedQueue", settings.Get("NServiceBus.Routing.EndpointName")); var topologyName = Environment.GetEnvironmentVariable("AzureServiceBusTransport.Topology", EnvironmentVariableTarget.User); topologyName = topologyName ?? Environment.GetEnvironmentVariable("AzureServiceBusTransport.Topology"); var transportExtension = new TransportExtensions <AzureServiceBusTransport>(settings); if (topologyName == "ForwardingTopology") { transportExtension.UseForwardingTopology(); } else { transportExtension.UseEndpointOrientedTopology(); } var transport = new AzureServiceBusTransport(); var infrastructure = transport.Initialize(settings, connectionString); return(new TransportConfigurationResult { PurgeInputQueueOnStartup = false, TransportInfrastructure = infrastructure }); }
public async Task Should_retry_immediately(TransportTransactionMode transactionMode) { var completed = new TaskCompletionSource <bool>(); OnTestTimeout(() => completed.SetCanceled()); var retrying = false; var retried = true; await StartPump( (context, _) => { if (retrying) { retried = true; return(Task.CompletedTask); } throw new Exception("Simulated exception"); }, (context, _) => { retrying = true; return(Task.FromResult(ErrorHandleResult.RetryRequired)); }, (_, __) => retried?completed.SetCompleted() : Task.CompletedTask, transactionMode); await SendMessage(InputQueueName); _ = await completed.Task; }
public async Task Should_not_emit_messages(TransportTransactionMode transactionMode) { var messageEmitted = false; var completed = new TaskCompletionSource <bool>(); OnTestTimeout(() => completed.SetCanceled()); await StartPump( async (context, _) => { if (context.Headers.ContainsKey("SentBeforeFailure")) { messageEmitted = true; return; } await SendMessage(InputQueueName, new Dictionary <string, string> { { "SentBeforeFailure", "" } }, context.TransportTransaction); throw new Exception("Simulated exception"); }, (errorContext, __) => Task.FromResult(ErrorHandleResult.Handled), (context, __) => completed.SetCompleted(), transactionMode); await SendMessage(InputQueueName); _ = await completed.Task; await StopPump(CancellationToken.None); Assert.False(messageEmitted); }
public async Task Should_not_raise_critical_error(TransportTransactionMode transactionMode) { var onErrorCalled = CreateTaskCompletionSource <bool>(); string criticalErrorDetails = null; await StartPump( (_, __) => { throw new Exception("from onMessage"); }, (_, __) => { onErrorCalled.TrySetResult(true); throw new ServiceBusException("from onError", ServiceBusFailureReason.ServiceTimeout); }, transactionMode, (msg, ex, ___) => { criticalErrorDetails = $"{msg}, Exception: {ex}"; } ); await SendMessage(InputQueueName); await onErrorCalled.Task; await StopPump(); Assert.IsNull(criticalErrorDetails, $"Should not invoke critical error for {nameof(ServiceBusException)}"); }
public Configuration(LogicalAddress logicalAddress, string queueNameBase, string localAddress, string instanceSpecificQueue, TransportTransactionMode transactionMode, PushRuntimeSettings pushRuntimeSettings, bool purgeOnStartup, Notification <ReceivePipelineCompleted> pipelineCompletedSubscribers, bool isSendOnlyEndpoint, List <Type> executeTheseHandlersFirst, MessageHandlerRegistry messageHandlerRegistry, bool createQueues, TransportSeam transportSeam) { LogicalAddress = logicalAddress; QueueNameBase = queueNameBase; LocalAddress = localAddress; InstanceSpecificQueue = instanceSpecificQueue; TransactionMode = transactionMode; PushRuntimeSettings = pushRuntimeSettings; PurgeOnStartup = purgeOnStartup; IsSendOnlyEndpoint = isSendOnlyEndpoint; PipelineCompletedSubscribers = pipelineCompletedSubscribers; ExecuteTheseHandlersFirst = executeTheseHandlersFirst; satelliteDefinitions = new List <SatelliteDefinition>(); this.messageHandlerRegistry = messageHandlerRegistry; CreateQueues = createQueues; this.transportSeam = transportSeam; }
public async Task Should_allow_message_processing_to_complete(TransportTransactionMode transactionMode) { var messageProcessingStarted = new TaskCompletionSource <bool>(); var messageProcessingCancelled = new TaskCompletionSource <bool>(); OnTestTimeout(() => { messageProcessingStarted.SetCanceled(); messageProcessingCancelled.SetCanceled(); }); await StartPump( async (_, cancellationToken) => { messageProcessingStarted.SetResult(true); try { await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken); } catch (OperationCanceledException) { messageProcessingCancelled.SetResult(true); } messageProcessingCancelled.SetResult(false); }, (_, __) => Task.FromResult(ErrorHandleResult.Handled), transactionMode); await SendMessage(InputQueueName); _ = await messageProcessingStarted.Task; await StopPump(default);
public async Task Should_cancel(TransportTransactionMode transactionMode) { var started = CreateTaskCompletionSource(); var wasCanceled = CreateTaskCompletionSource <bool>(); await StartPump( async (_, cancellationToken) => { started.SetResult(); try { await Task.Delay(TestTimeout, cancellationToken); } catch (Exception ex) when(ex.IsCausedBy(cancellationToken)) { wasCanceled.SetResult(true); throw; } wasCanceled.SetResult(false); }, (_, __) => Task.FromResult(ErrorHandleResult.Handled), transactionMode); await SendMessage(InputQueueName); await started.Task; await StopPump(new CancellationToken(true)); Assert.True(await wasCanceled.Task, "onMessage was not canceled."); }
public async Task Should_emit_messages(TransportTransactionMode transactionMode) { var completed = new TaskCompletionSource <bool>(); OnTestTimeout(() => completed.SetCanceled()); await StartPump( async (context, _) => { if (context.Headers.ContainsKey("IsolatedSend")) { return; } await SendMessage( InputQueueName, new Dictionary <string, string> { { "IsolatedSend", "" } }, context.TransportTransaction, dispatchConsistency: DispatchConsistency.Isolated); throw new Exception("Simulated exception"); }, (errorContext, __) => Task.FromResult(ErrorHandleResult.Handled), (context, __) => context.Headers.ContainsKey("IsolatedSend")?completed.SetCompleted() : Task.CompletedTask, transactionMode); await SendMessage(InputQueueName); _ = await completed.Task; }
public async Task Should_roll_back(TransportTransactionMode transactionMode) { var retried = CreateTaskCompletionSource <MessageContext>(); var retrying = false; await StartPump( (context, _) => { if (retrying) { return(retried.SetCompleted(context)); } context.Headers["test-header"] = "modified"; throw new Exception(); }, (context, _) => { retrying = true; return(Task.FromResult(ErrorHandleResult.RetryRequired)); }, transactionMode); await SendMessage(InputQueueName, new Dictionary <string, string> { { "test-header", "original" } }); var retryMessageContext = await retried.Task; Assert.AreEqual("original", retryMessageContext.Headers["test-header"]); }
public TransportConfigurationResult Configure(SettingsHolder settings, TransportTransactionMode transportTransactionMode) { #if !NETFRAMEWORK if (transportTransactionMode == TransportTransactionMode.TransactionScope) { NUnit.Framework.Assert.Ignore("TransactionScope not supported in .NET Core"); } #endif this.settings = settings; settings.Set(transportTransactionMode); settings.Set("NServiceBus.SharedQueue", settings.EndpointName()); var delayedDeliverySettings = new DelayedDeliverySettings(settings); delayedDeliverySettings.TableSuffix("Delayed"); var pubSubSettings = new SubscriptionSettings(); pubSubSettings.DisableSubscriptionCache(); settings.Set(pubSubSettings); connectionString = Environment.GetEnvironmentVariable("SqlServerTransportConnectionString"); if (string.IsNullOrEmpty(connectionString)) { connectionString = @"Data Source=.\SQLEXPRESS;Initial Catalog=nservicebus;Integrated Security=True"; } var logicalAddress = LogicalAddress.CreateLocalAddress(settings.ErrorQueueAddress(), new Dictionary <string, string>()); var localAddress = settings.EndpointName(); return(new TransportConfigurationResult { TransportInfrastructure = new SqlServerTransportInfrastructure("nservicebus", settings, connectionString, () => localAddress, () => logicalAddress, false) }); }
public async Task Should_dispatch_the_message(TransportTransactionMode transactionMode) { var messageReceived = new TaskCompletionSource <bool>(); OnTestTimeout(() => messageReceived.SetResult(false)); await StartPump( (context, _) => { if (context.Headers.ContainsKey("FromOnError")) { messageReceived.SetResult(true); return(Task.FromResult(0)); } throw new Exception("Simulated exception"); }, async (context, _) => { await SendMessage(InputQueueName, new Dictionary <string, string> { { "FromOnError", "true" } }, context.TransportTransaction); return(ErrorHandleResult.Handled); }, transactionMode); await SendMessage(InputQueueName); Assert.True(await messageReceived.Task, "Message not dispatched properly"); }
public async Task Should_cancel(TransportTransactionMode transactionMode) { var started = CreateTaskCompletionSource(); var wasCancelled = CreateTaskCompletionSource <bool>(); await StartPump( (_, __) => throw new Exception(), async (_, cancellationToken) => { started.SetResult(); try { await Task.Delay(TestTimeout, cancellationToken); } catch (OperationCanceledException) { wasCancelled.SetResult(true); throw; } wasCancelled.SetResult(false); return(ErrorHandleResult.Handled); }, transactionMode); await SendMessage(InputQueueName); await started.Task; await StopPump(new CancellationToken(true)); Assert.True(await wasCancelled.Task, "onError was not cancelled."); }
public async Task Should_invoke_on_message(TransportTransactionMode transactionMode) { var onMessageCalled = new TaskCompletionSource<MessageContext>(); OnTestTimeout(() => onMessageCalled.SetCanceled()); await StartPump(context => { var body = Encoding.UTF8.GetString(context.Body); Assert.AreEqual("", body, "Should pass the body"); onMessageCalled.SetResult(context); return Task.FromResult(0); }, context => Task.FromResult(ErrorHandleResult.Handled), transactionMode); await SendMessage(InputQueueName, new Dictionary<string, string> { {"MyHeader", "MyValue"} }); var messageContext = await onMessageCalled.Task; Assert.False(string.IsNullOrEmpty(messageContext.MessageId), "Should pass the native message id"); Assert.AreEqual("MyValue", messageContext.Headers["MyHeader"], "Should pass the message headers"); }
public TransportConfigurationResult Configure(SettingsHolder settings, TransportTransactionMode transactionMode) { var result = new TransportConfigurationResult(); var transport = new RabbitMQTransport(); var connectionString = Environment.GetEnvironmentVariable("RabbitMQTransport_ConnectionString"); if (string.IsNullOrEmpty(connectionString)) { throw new Exception("The 'RabbitMQTransport_ConnectionString' environment variable is not set."); } connectionStringBuilder = new DbConnectionStringBuilder { ConnectionString = connectionString }; queueBindings = settings.Get <QueueBindings>(); new TransportExtensions <RabbitMQTransport>(settings).UseConventionalRoutingTopology(); result.TransportInfrastructure = transport.Initialize(settings, connectionStringBuilder.ConnectionString); isTransportInitialized = true; result.PurgeInputQueueOnStartup = true; transportTransactionMode = result.TransportInfrastructure.TransactionMode; requestedTransactionMode = transactionMode; //work around for TransportTests not calling Start result.TransportInfrastructure.Start(); return(result); }
static DispatchConsistency GetDispatchConsistency(TransportTransactionMode transportTransactionMode) { // dispatch message isolated from existing transactions when not using DTC to avoid loosing timeout data when the transaction commit fails. return transportTransactionMode == TransportTransactionMode.TransactionScope ? DispatchConsistency.Default : DispatchConsistency.Isolated; }
public async Task Should_invoke_critical_error(TransportTransactionMode transactionMode) { var recoverabilityStarted = new TaskCompletionSource <bool>(); var criticalErrorInvoked = false; OnTestTimeout(() => recoverabilityStarted.SetCanceled()); await StartPump( (_, __) => throw new Exception(), (_, cancellationToken) => { recoverabilityStarted.SetResult(true); throw new OperationCanceledException(); }, transactionMode, (_, __, ___) => criticalErrorInvoked = true); await SendMessage(InputQueueName); _ = await recoverabilityStarted.Task; await Task.Delay(TimeSpan.FromSeconds(1)); await StopPump(default);
public async Task Should_reset_delivery_counter(TransportTransactionMode transactionMode) { var onErrorInvoked = new TaskCompletionSource<ErrorContext>(); OnTestTimeout(() => onErrorInvoked.SetCanceled()); var numberOfOnErrorInvocations = 0; await StartPump( context => { throw new Exception("Simulated exception"); }, async context => { numberOfOnErrorInvocations += 1; if (numberOfOnErrorInvocations == 1) { await SendMessage(InputQueueName, context.Message.Headers, context.TransportTransaction); } else { onErrorInvoked.SetResult(context); } return ErrorHandleResult.Handled; }, transactionMode); await SendMessage(InputQueueName, new Dictionary<string, string> { { "MyHeader", "MyValue" } }); var errorContext = await onErrorInvoked.Task; Assert.AreEqual(1, errorContext.ImmediateProcessingFailures, "Should track delivery attempts between immediate retries"); }
public async Task Should_emit_messages(TransportTransactionMode transactionMode) { var messageEmitted = CreateTaskCompletionSource(); await StartPump( async (context, _) => { if (context.Headers.ContainsKey("IsolatedSend")) { messageEmitted.SetResult(); return; } await SendMessage( InputQueueName, new Dictionary <string, string> { { "IsolatedSend", "" } }, context.TransportTransaction, dispatchConsistency: DispatchConsistency.Isolated); throw new Exception("Simulated exception"); }, (_, __) => Task.FromResult(ErrorHandleResult.Handled), transactionMode); await SendMessage(InputQueueName); await messageEmitted.Task; }
public async Task Should_invoke_recoverability(TransportTransactionMode transactionMode) { var messageProcessingStarted = new TaskCompletionSource <bool>(); var recoverabilityInvoked = false; OnTestTimeout(() => messageProcessingStarted.SetCanceled()); await StartPump( (context, _) => { messageProcessingStarted.SetResult(true); throw new OperationCanceledException(); }, (_, __) => { recoverabilityInvoked = true; return(Task.FromResult(ErrorHandleResult.Handled)); }, transactionMode); await SendMessage(InputQueueName); _ = await messageProcessingStarted.Task; await Task.Delay(TimeSpan.FromSeconds(1)); await StopPump(default);
public async Task Should_move_to_error_queue(TransportTransactionMode transactionMode) { var onMessageCalled = false; var onErrorCalled = false; var cancellationTokenSource = new CancellationTokenSource(); OnTestTimeout(() => cancellationTokenSource.Cancel()); await StartPump( context => { onMessageCalled = true; return(Task.FromResult(0)); }, context => { onErrorCalled = true; return(Task.FromResult(ErrorHandleResult.Handled)); }, transactionMode); await SendPoisonMessage(InputQueueName); await CheckErrorQueue(ErrorQueueName, cancellationTokenSource.Token); Assert.False(onErrorCalled, "Poison message should not invoke onError"); Assert.False(onMessageCalled, "Poison message should not invoke onMessage"); }
public async Task Should_invoke_on_message(TransportTransactionMode transactionMode) { MessageContext messageContext = null; var completed = new TaskCompletionSource <CompleteContext>(); OnTestTimeout(() => completed.SetCanceled()); await StartPump( (context, _) => { messageContext = context; return(Task.CompletedTask); }, (context, _) => Task.FromResult(ErrorHandleResult.Handled), (context, _) => completed.SetCompleted(context), transactionMode); await SendMessage(InputQueueName, new Dictionary <string, string> { { "MyHeader", "MyValue" } }, body : new byte[] { 1, 2, 3 }); var completeContext = await completed.Task; Assert.False(completeContext.OnMessageFailed, "Message failure should not be indicated"); Assert.NotNull(messageContext, "On message should have been called"); Assert.False(string.IsNullOrEmpty(messageContext.NativeMessageId), "Should pass the native message id"); Assert.AreEqual("MyValue", messageContext.Headers["MyHeader"], "Should pass the message headers"); Assert.AreEqual(new byte[] { 1, 2, 3 }, messageContext.Body, "Should pass the body"); }
public async Task Should_not_invoke_recoverability(TransportTransactionMode transactionMode) { var messageProcessingStarted = new TaskCompletionSource <bool>(); var recoverabilityInvoked = false; OnTestTimeout(() => messageProcessingStarted.SetCanceled()); await StartPump( async (_, cancellationToken) => { messageProcessingStarted.SetResult(true); await Task.Delay(TestTimeout, cancellationToken); }, (_, __) => { recoverabilityInvoked = true; return(Task.FromResult(ErrorHandleResult.Handled)); }, transactionMode); await SendMessage(InputQueueName); _ = await messageProcessingStarted.Task; await StopPump(new CancellationToken(true)); Assert.False(recoverabilityInvoked); }
public async Task Should_call_on_error_and_indicate_failure(TransportTransactionMode transactionMode) { ErrorContext errorContext = null; var completed = new TaskCompletionSource <CompleteContext>(); OnTestTimeout(() => completed.SetCanceled()); await StartPump( (context, _) => throw new Exception("Simulated exception"), (context, _) => { errorContext = context; return(Task.FromResult(ErrorHandleResult.Handled)); }, (context, _) => completed.SetCompleted(context), transactionMode); await SendMessage(InputQueueName, new Dictionary <string, string> { { "MyHeader", "MyValue" } }); var completeContext = await completed.Task; Assert.NotNull(errorContext, "On error should have been called"); Assert.AreEqual(errorContext.Exception.Message, "Simulated exception", "Should preserve the exception"); Assert.AreEqual(1, errorContext.ImmediateProcessingFailures, "Should track the number of delivery attempts"); Assert.AreEqual("MyValue", errorContext.Message.Headers["MyHeader"], "Should pass the message headers"); Assert.True(completeContext.OnMessageFailed, "Message failure should be indicated"); Assert.True(completeContext.WasAcknowledged, "Message should be acknowleged"); }
void IgnoreUnsupportedTransactionModes(TransportTransactionMode requestedTransactionMode) { if (TransportInfrastructure.TransactionMode < requestedTransactionMode) { Assert.Ignore($"Only relevant for transports supporting {requestedTransactionMode} or higher"); } }
static DispatchConsistency GetDispatchConsistency(TransportTransactionMode transportTransactionMode) { // dispatch message isolated from existing transactions when not using DTC to avoid loosing timeout data when the transaction commit fails. return(transportTransactionMode == TransportTransactionMode.TransactionScope ? DispatchConsistency.Default : DispatchConsistency.Isolated); }
public async Task Should_invoke_critical_error(TransportTransactionMode transactionMode) { var criticalErrorInvoked = false; var completed = new TaskCompletionSource <CompleteContext>(); OnTestTimeout(() => completed.SetCanceled()); await StartPump( (_, __) => throw new Exception(), (_, __) => throw new OperationCanceledException(), (context, _) => completed.SetCompleted(context), transactionMode, (_, __, ___) => criticalErrorInvoked = true); await SendMessage(InputQueueName); var completeContext = await completed.Task; await StopPump(); Assert.True(criticalErrorInvoked); Assert.False(completeContext.WasAcknowledged); Assert.True(completeContext.OnMessageFailed); }
public async Task Should_emit_messages(TransportTransactionMode transactionMode) { var onMessageCalled = new TaskCompletionSource <bool>(); OnTestTimeout(() => onMessageCalled.SetCanceled()); await StartPump(async context => { if (context.Headers.ContainsKey("IsolatedSend")) { onMessageCalled.SetResult(true); return; } await SendMessage(InputQueueName, new Dictionary <string, string> { { "IsolatedSend", "true" } }, context.TransportTransaction, null, DispatchConsistency.Isolated); throw new Exception("Simulated exception"); }, errorContext => Task.FromResult(ErrorHandleResult.Handled), transactionMode); await SendMessage(InputQueueName); Assert.True(await onMessageCalled.Task, "Should emit isolated sends"); }
public async Task SmokeTest(TransportTransactionMode transactionMode) { var endpointConfiguration = EndpointConfigBuilder.BuildEndpoint(nameof(SqlTransportIntegrationTests)); var typesToScan = TypeScanner.NestedTypes <SqlTransportIntegrationTests>(); endpointConfiguration.SetTypesToScan(typesToScan); var transport = endpointConfiguration.UseTransport <SqlServerTransport>(); transport.Transactions(transactionMode); transport.UseCustomSqlConnectionFactory(async() => { var connection = MsSqlConnectionBuilder.Build(); await connection.OpenAsync().ConfigureAwait(false); return(connection); }); var persistence = endpointConfiguration.UsePersistence <SqlPersistence>(); persistence.SqlDialect <SqlDialect.MsSqlServer>(); persistence.ConnectionBuilder(MsSqlConnectionBuilder.Build); persistence.DisableInstaller(); persistence.SubscriptionSettings().DisableCache(); var endpoint = await Endpoint.Start(endpointConfiguration).ConfigureAwait(false); var startSagaMessage = new StartSagaMessage { StartId = Guid.NewGuid() }; await endpoint.SendLocal(startSagaMessage).ConfigureAwait(false); ManualResetEvent.WaitOne(); await endpoint.Stop().ConfigureAwait(false); }
public SatelliteDefinition(string name, string receiveAddress, TransportTransactionMode requiredTransportTransactionMode, PushRuntimeSettings runtimeSettings, Func<RecoverabilityConfig, ErrorContext, RecoverabilityAction> recoverabilityPolicy, Func<IBuilder, MessageContext, Task> onMessage) { Name = name; ReceiveAddress = receiveAddress; RequiredTransportTransactionMode = requiredTransportTransactionMode; RuntimeSettings = runtimeSettings; RecoverabilityPolicy = recoverabilityPolicy; OnMessage = onMessage; }
public TransportConfigurationResult Configure(SettingsHolder settings, TransportTransactionMode transactionMode) { var msmqTransportDefinition = new MsmqTransport(); settingsHolder = settings; return new TransportConfigurationResult { TransportInfrastructure = msmqTransportDefinition.Initialize(settingsHolder, ""), PurgeInputQueueOnStartup = true }; }
/// <summary> /// Creates an instance of <see cref="PushSettings" />. /// </summary> /// <param name="inputQueue">Input queue name.</param> /// <param name="errorQueue">Error queue name.</param> /// <param name="purgeOnStartup"><code>true</code> to purge <paramref name="inputQueue" /> at startup.</param> /// <param name="requiredTransactionMode">The transaction mode required for receive operations.</param> public PushSettings(string inputQueue, string errorQueue, bool purgeOnStartup, TransportTransactionMode requiredTransactionMode) { Guard.AgainstNullAndEmpty(nameof(inputQueue), inputQueue); Guard.AgainstNullAndEmpty(nameof(errorQueue), errorQueue); Guard.AgainstNull(nameof(requiredTransactionMode), requiredTransactionMode); PurgeOnStartup = purgeOnStartup; RequiredTransactionMode = requiredTransactionMode; InputQueue = inputQueue; ErrorQueue = errorQueue; }
ReceiveStrategy SelectReceiveStrategy(TransportTransactionMode minimumConsistencyGuarantee, TransactionOptions transactionOptions) { switch (minimumConsistencyGuarantee) { case TransportTransactionMode.TransactionScope: return new TransactionScopeStrategy(transactionOptions, new MsmqFailureInfoStorage(1000)); case TransportTransactionMode.SendsAtomicWithReceive: return new SendsAtomicWithReceiveNativeTransactionStrategy(new MsmqFailureInfoStorage(1000)); case TransportTransactionMode.ReceiveOnly: return new ReceiveOnlyNativeTransactionStrategy(new MsmqFailureInfoStorage(1000)); case TransportTransactionMode.None: return new NoTransactionStrategy(); default: throw new NotSupportedException($"TransportTransactionMode {minimumConsistencyGuarantee} is not supported by the MSMQ transport"); } }
static string SetupDispatcherSatellite(FeatureConfigurationContext context, TransportTransactionMode requiredTransactionSupport, PushRuntimeSettings pushRuntimeSettings) { var satelliteLogicalAddress = context.Settings.LogicalAddress().CreateQualifiedAddress("TimeoutsDispatcher"); var satelliteAddress = context.Settings.GetTransportAddress(satelliteLogicalAddress); context.AddSatelliteReceiver("Timeout Dispatcher Processor", satelliteAddress, requiredTransactionSupport, pushRuntimeSettings, RecoverabilityPolicy, (builder, pushContext) => { var dispatchBehavior = new DispatchTimeoutBehavior( builder.Build<IDispatchMessages>(), builder.Build<IPersistTimeouts>(), requiredTransactionSupport); return dispatchBehavior.Invoke(pushContext); }); return satelliteAddress; }
static void SetupStorageSatellite(FeatureConfigurationContext context, TransportTransactionMode requiredTransactionSupport, PushRuntimeSettings pushRuntimeSettings) { var satelliteLogicalAddress = context.Settings.LogicalAddress().CreateQualifiedAddress("Timeouts"); var satelliteAddress = context.Settings.GetTransportAddress(satelliteLogicalAddress); context.AddSatelliteReceiver("Timeout Message Processor", satelliteAddress, requiredTransactionSupport, pushRuntimeSettings, RecoverabilityPolicy, (builder, pushContext) => { var storeBehavior = new StoreTimeoutBehavior( builder.Build<ExpiredTimeoutsPoller>(), builder.Build<IDispatchMessages>(), builder.Build<IPersistTimeouts>(), context.Settings.EndpointName().ToString()); return storeBehavior.Invoke(pushContext); }); context.Settings.Get<TimeoutManagerAddressConfiguration>().Set(satelliteAddress); }
public async Task Should_invoke_on_message(TransportTransactionMode transactionMode) { RequireDeliveryConstraint<NonDurableDelivery>(); var onMessageCalled = new TaskCompletionSource<MessageContext>(); OnTestTimeout(() => onMessageCalled.SetCanceled()); await StartPump(context => { onMessageCalled.SetResult(context); return Task.FromResult(0); }, context => Task.FromResult(ErrorHandleResult.Handled), transactionMode); await SendMessage(InputQueueName, deliveryConstraints: new List<DeliveryConstraint> { new NonDurableDelivery() }); var messageContext = await onMessageCalled.Task; Assert.NotNull(messageContext); }
public async Task Should_move_it_to_the_error_queue(TransportTransactionMode transactionMode) { DeleteQueue(); try { await Scenario.Define<Context>() .WithEndpoint<Endpoint>(b => { b.CustomConfig(c => { c.UseTransport<MsmqTransport>() .Transactions(transactionMode); }); b.When((session, c) => { var endpoint = AcceptanceTesting.Customization.Conventions.EndpointNamingConvention(typeof(Endpoint)); var inputQueue = $@".\private$\{endpoint}"; using (var queue = new MessageQueue(inputQueue)) using (var message = new Message()) { message.Extension = Encoding.UTF8.GetBytes("<badheaders"); queue.Send(message, MessageQueueTransactionType.Single); } return Task.FromResult(0); }); }) .Done(c => c.Logs.Any(l => l.Level == LogLevel.Error)) .Run(); Assert.True(MessageExistsInErrorQueue(), "The message should have been moved to the error queue"); } finally { DeleteQueue(); } }
public async Task Should_reinvoke_on_error_with_original_exception(TransportTransactionMode transactionMode) { var onErrorCalled = new TaskCompletionSource<ErrorContext>(); Exception criticalError = null; OnTestTimeout(() => onErrorCalled.SetCanceled()); var firstInvocation = true; await StartPump( context => { throw new Exception("Simulated exception"); }, context => { if (firstInvocation) { firstInvocation = false; throw new Exception("Exception from onError"); } onErrorCalled.SetResult(context); return Task.FromResult(ErrorHandleResult.Handled); }, transactionMode, (s, exception) => criticalError = exception); await SendMessage(InputQueueName); var errorContext = await onErrorCalled.Task; Assert.AreEqual("Simulated exception", errorContext.Exception.Message); Assert.AreEqual(2, errorContext.ImmediateProcessingFailures); Assert.IsNotNull(criticalError); }
public async Task Should_not_emit_messages(TransportTransactionMode transactionMode) { var onMessageCalled = new TaskCompletionSource<bool>(); OnTestTimeout(() => onMessageCalled.SetCanceled()); await StartPump(async context => { if (context.Headers.ContainsKey("CompleteTest")) { onMessageCalled.SetResult(true); return; } if (context.Headers.ContainsKey("EnlistedSend")) { onMessageCalled.SetResult(false); return; } await SendMessage(InputQueueName, new Dictionary<string, string> { { "EnlistedSend", "true" } }, context.TransportTransaction); throw new Exception("Simulated exception"); }, async context => { await SendMessage(InputQueueName, new Dictionary<string, string> { { "CompleteTest", "true" } }, context.TransportTransaction); return ErrorHandleResult.Handled; }, transactionMode); await SendMessage(InputQueueName, new Dictionary<string, string> { { "MyHeader", "MyValue" } }); Assert.True(await onMessageCalled.Task, "Should not emit enlisted sends"); }
public DispatchTimeoutBehavior(IDispatchMessages dispatcher, IPersistTimeouts persister, TransportTransactionMode transportTransactionMode) { this.dispatcher = dispatcher; this.persister = persister; dispatchConsistency = GetDispatchConsistency(transportTransactionMode); }
List<TransportReceiver> BuildMainReceivers(string errorQueue, bool purgeOnStartup, TransportTransactionMode requiredTransactionSupport, RecoverabilityExecutorFactory recoverabilityExecutorFactory, IPipeline<ITransportReceiveContext> mainPipeline) { var localAddress = settings.LocalAddress(); var distributorAddress = settings.GetOrDefault<string>("LegacyDistributor.Address"); var recoverabilityExecutor = recoverabilityExecutorFactory.CreateDefault(eventAggregator, distributorAddress ?? localAddress); var pushSettings = new PushSettings(settings.LocalAddress(), errorQueue, purgeOnStartup, requiredTransactionSupport); var mainPipelineExecutor = new MainPipelineExecutor(builder, eventAggregator, pipelineCache, mainPipeline); var dequeueLimitations = GetDequeueLimitationsForReceivePipeline(); var receivers = new List<TransportReceiver>(); receivers.Add(new TransportReceiver(MainReceiverId, builder.Build<IPushMessages>(), pushSettings, dequeueLimitations, mainPipelineExecutor, recoverabilityExecutor, criticalError)); if (settings.InstanceSpecificQueue() != null) { var instanceSpecificQueue = settings.InstanceSpecificQueue(); var instanceSpecificRecoverabilityExecutor = recoverabilityExecutorFactory.CreateDefault(eventAggregator, instanceSpecificQueue); var sharedReceiverPushSettings = new PushSettings(settings.InstanceSpecificQueue(), errorQueue, purgeOnStartup, requiredTransactionSupport); receivers.Add(new TransportReceiver(MainReceiverId, builder.Build<IPushMessages>(), sharedReceiverPushSettings, dequeueLimitations, mainPipelineExecutor, instanceSpecificRecoverabilityExecutor, criticalError)); } return receivers; }
public FakeRavenDBTransportInfrastructure(TransportTransactionMode transactionMode) { this.transactionMode = transactionMode; }
public async Task Invoke_when_not_using_dtc_transport_should_not_enlist_dispatch_in_transaction(TransportTransactionMode nonDtcTxSettings) { var messageDispatcher = new FakeMessageDispatcher(); var timeoutPersister = new InMemoryTimeoutPersister(() => DateTime.UtcNow); var behavior = new DispatchTimeoutBehavior(messageDispatcher, timeoutPersister, nonDtcTxSettings); var timeoutData = CreateTimeout(); await timeoutPersister.Add(timeoutData, null); await behavior.Invoke(CreateContext(timeoutData.Id)); var transportOperation = messageDispatcher.OutgoingTransportOperations.UnicastTransportOperations.Single(); Assert.AreEqual(DispatchConsistency.Isolated, transportOperation.RequiredDispatchConsistency); }