/// <summary> /// Creates a new transport operation. /// </summary> /// <param name="message">The message to dispatch.</param> /// <param name="addressTag">The address to use when routing this message.</param> /// <param name="requiredDispatchConsistency">The required consistency level for the dispatch operation.</param> /// <param name="properties">Delivery properties of the message.</param> public TransportOperation(OutgoingMessage message, AddressTag addressTag, DispatchProperties properties = null, DispatchConsistency requiredDispatchConsistency = DispatchConsistency.Default) { Message = message; AddressTag = addressTag; Properties = properties ?? new DispatchProperties(); RequiredDispatchConsistency = requiredDispatchConsistency; }
/// <summary> /// Creates a new transport operation. /// </summary> /// <param name="message">The message to dispatch.</param> /// <param name="addressTag">The address to use when routing this message.</param> /// <param name="requiredDispatchConsistency">The required consistency level for the dispatch operation.</param> /// <param name="deliveryConstraints">The delivery constraints that must be honored by the transport.</param> public TransportOperation(OutgoingMessage message, AddressTag addressTag, DispatchConsistency requiredDispatchConsistency = DispatchConsistency.Default, List<DeliveryConstraint> deliveryConstraints = null) { Message = message; AddressTag = addressTag; RequiredDispatchConsistency = requiredDispatchConsistency; DeliveryConstraints = deliveryConstraints ?? DeliveryConstraint.EmptyConstraints; }
/// <summary> /// Creates a new transport operation. /// </summary> /// <param name="message">The message to dispatch.</param> /// <param name="addressTag">The address to use when routing this message.</param> /// <param name="requiredDispatchConsistency">The required consistency level for the dispatch operation.</param> /// <param name="deliveryConstraints">The delivery constraints that must be honored by the transport.</param> public TransportOperation(OutgoingMessage message, AddressTag addressTag, DispatchConsistency requiredDispatchConsistency = DispatchConsistency.Default, List <DeliveryConstraint> deliveryConstraints = null) { Message = message; AddressTag = addressTag; RequiredDispatchConsistency = requiredDispatchConsistency; DeliveryConstraints = deliveryConstraints ?? new List <DeliveryConstraint>(0); }
/// <summary> /// Creates a new <see cref="MulticastTransportOperation" /> instance. /// </summary> // ReSharper disable once ParameterTypeCanBeEnumerable.Local public MulticastTransportOperation(OutgoingMessage message, Type messageType, DispatchConsistency requiredDispatchConsistency = DispatchConsistency.Default, List<DeliveryConstraint> deliveryConstraints = null) { Message = message; MessageType = messageType; DeliveryConstraints = deliveryConstraints ?? DeliveryConstraint.EmptyConstraints; RequiredDispatchConsistency = requiredDispatchConsistency; }
/// <summary> /// Creates a new <see cref="MulticastTransportOperation" /> instance. /// </summary> public MulticastTransportOperation(OutgoingMessage message, Type messageType, DispatchProperties properties, DispatchConsistency requiredDispatchConsistency = DispatchConsistency.Default) { Message = message; MessageType = messageType; Properties = properties; RequiredDispatchConsistency = requiredDispatchConsistency; }
/// <summary> /// Creates a new <see cref="MulticastTransportOperation" /> instance. /// </summary> // ReSharper disable once ParameterTypeCanBeEnumerable.Local public MulticastTransportOperation(OutgoingMessage message, Type messageType, DispatchConsistency requiredDispatchConsistency = DispatchConsistency.Default, List <DeliveryConstraint> deliveryConstraints = null) { Message = message; MessageType = messageType; DeliveryConstraints = deliveryConstraints ?? DeliveryConstraint.EmptyConstraints; RequiredDispatchConsistency = requiredDispatchConsistency; }
protected Task SendMessage( string address, Dictionary <string, string> headers = null, TransportTransaction transportTransaction = null, DispatchProperties dispatchProperties = null, DispatchConsistency dispatchConsistency = DispatchConsistency.Default, byte[] body = null) { var messageId = Guid.NewGuid().ToString(); var message = new OutgoingMessage(messageId, headers ?? new Dictionary <string, string>(), body ?? Array.Empty <byte>()); if (message.Headers.ContainsKey(TestIdHeaderName) == false) { message.Headers.Add(TestIdHeaderName, testId); } if (transportTransaction == null) { transportTransaction = new TransportTransaction(); } var transportOperation = new TransportOperation(message, new UnicastAddressTag(address), dispatchProperties, dispatchConsistency); return(transportInfrastructure.Dispatcher.Dispatch(new TransportOperations(transportOperation), transportTransaction)); }
/// <summary> /// Creates a new <see cref="UnicastTransportOperation" /> instance. /// </summary> public UnicastTransportOperation(OutgoingMessage message, string destination, DispatchProperties properties, DispatchConsistency requiredDispatchConsistency = DispatchConsistency.Default) { Message = message; Destination = destination; Properties = properties; RequiredDispatchConsistency = requiredDispatchConsistency; }
/// <summary> /// Creates a new <see cref="UnicastTransportOperation" /> instance. /// </summary> public UnicastTransportOperation(OutgoingMessage message, string destination, DispatchConsistency requiredDispatchConsistency = DispatchConsistency.Default, List<DeliveryConstraint> deliveryConstraints = null) { Message = message; Destination = destination; DeliveryConstraints = deliveryConstraints ?? DeliveryConstraint.EmptyConstraints; RequiredDispatchConsistency = requiredDispatchConsistency; }
bool IsCombiningTimeToBeReceivedWithTransactions(TransportTransaction transaction, DispatchConsistency requiredDispatchConsistency, DispatchProperties dispatchProperties) { if (!transportSettings.UseTransactionalQueues) { return(false); } if (requiredDispatchConsistency == DispatchConsistency.Isolated) { return(false); } var timeToBeReceivedRequested = dispatchProperties.DiscardIfNotReceivedBefore?.MaxTime < MessageQueue.InfiniteTimeout; if (!timeToBeReceivedRequested) { return(false); } if (Transaction.Current != null) { return(true); } return(TryGetNativeTransaction(transaction, out _)); }
protected Task SendMessage(string address, Dictionary <string, string> headers = null, TransportTransaction transportTransaction = null, List <DeliveryConstraint> deliveryConstraints = null, DispatchConsistency dispatchConsistency = DispatchConsistency.Default) { var messageId = Guid.NewGuid().ToString(); var message = new OutgoingMessage(messageId, headers ?? new Dictionary <string, string>(), new byte[0]); if (message.Headers.ContainsKey(TestIdHeaderName) == false) { message.Headers.Add(TestIdHeaderName, testId); } var dispatcher = lazyDispatcher.Value; if (transportTransaction == null) { transportTransaction = new TransportTransaction(); } var transportOperation = new TransportOperation(message, new UnicastAddressTag(address), dispatchConsistency, deliveryConstraints ?? new List <DeliveryConstraint>()); return(dispatcher.Dispatch(new TransportOperations(transportOperation), transportTransaction, new ContextBag())); }
/// <summary> /// Creates a new <see cref="UnicastTransportOperation" /> instance. /// </summary> public UnicastTransportOperation(OutgoingMessage message, string destination, DispatchConsistency requiredDispatchConsistency = DispatchConsistency.Default, List <DeliveryConstraint> deliveryConstraints = null) { Message = message; Destination = destination; DeliveryConstraints = deliveryConstraints ?? new List <DeliveryConstraint>(0); RequiredDispatchConsistency = requiredDispatchConsistency; }
public async Task Should_recover(Type contextProviderType, DispatchConsistency dispatchConsistency) { // Setup var token = CancellationToken.None; var connectionString = Environment.GetEnvironmentVariable("SqlServerTransportConnectionString") ?? @"Data Source=.\SQLEXPRESS;Initial Catalog=nservicebus;Integrated Security=True"; sqlConnectionFactory = SqlConnectionFactory.Default(connectionString); var addressParser = new QueueAddressTranslator("nservicebus", "dbo", null, null); var purger = new QueuePurger(sqlConnectionFactory); await RemoveQueueIfPresent(QueueName, token); await RemoveQueueIfPresent($"{QueueName}.Delayed", token); await CreateOutputQueueIfNecessary(addressParser, sqlConnectionFactory); var tableCache = new TableBasedQueueCache(addressParser, true); var queue = tableCache.Get(QueueName); dispatcher = new MessageDispatcher(addressParser, new NoOpMulticastToUnicastConverter(), tableCache, null, sqlConnectionFactory); // Run normally int messagesSent = await RunTest(contextProviderType, dispatchConsistency, queue, purger, token); Assert.AreEqual(1, messagesSent); // Remove Recoverable column await DropRecoverableColumn(token); var exception = Assert.ThrowsAsync <Exception>(() => RunTest(contextProviderType, dispatchConsistency, queue, purger, token)); Assert.True(exception.Message.Contains("change in the existence of the Recoverable column")); // Try again, should work int messagesSentAttempt2 = await RunTest(contextProviderType, dispatchConsistency, queue, purger, token); Assert.AreEqual(1, messagesSentAttempt2); // Put the Recoverable column back await AddRecoverableColumn(token); var exception2 = Assert.ThrowsAsync <Exception>(() => RunTest(contextProviderType, dispatchConsistency, queue, purger, token)); Assert.True(exception2.Message.Contains("change in the existence of the Recoverable column")); // Try again, should work int messagesSentAttempt3 = await RunTest(contextProviderType, dispatchConsistency, queue, purger, token); Assert.AreEqual(1, messagesSentAttempt3); }
async Task <int> RunTest(Type contextProviderType, DispatchConsistency dispatchConsistency, TableBasedQueue queue, QueuePurger purger, CancellationToken cancellationToken) { using (var contextProvider = CreateContext(contextProviderType, sqlConnectionFactory)) { // Run with Recoverable column in place var operations = new TransportOperations(CreateTransportOperation(id: "1", destination: QueueName, consistency: dispatchConsistency)); await dispatcher.Dispatch(operations, contextProvider.TransportTransaction, cancellationToken); contextProvider.Complete(); return(await purger.Purge(queue, cancellationToken)); } }
RoutingOptions GetRoutingOptions(ReceiveContext receiveContext, DispatchConsistency consistency) { var sendVia = false; var context = receiveContext as BrokeredMessageReceiveContext; if (context?.Recovering == false) // avoid send via when recovering to prevent error message from rolling back { sendVia = settings.Get <bool>(WellKnownConfigurationKeys.Connectivity.SendViaReceiveQueue); sendVia &= settings.Get <TransportType>(WellKnownConfigurationKeys.Connectivity.TransportType) == TransportType.NetMessaging; sendVia &= consistency != DispatchConsistency.Isolated; } return(new RoutingOptions { SendVia = sendVia, ViaEntityPath = GetViaEntityPathFor(context?.Entity), ViaConnectionString = context?.Entity.Namespace.ConnectionString, ViaPartitionKey = context?.IncomingBrokeredMessage.PartitionKey }); }
internal Task RouteBatch(Batch batch, BrokeredMessageReceiveContext context, DispatchConsistency consistency) { var outgoingBatches = batch.Operations; var passiveNamespaces = batch.Destinations.Namespaces.Where(n => n.Mode == NamespaceMode.Passive).ToList(); var pendingSends = new List <Task>(); foreach (var entity in batch.Destinations.Entities.Where(entity => entity.Namespace.Mode == NamespaceMode.Active)) { var routingOptions = GetRoutingOptions(context, consistency); if (!string.IsNullOrEmpty(routingOptions.ViaEntityPath)) { Logger.DebugFormat("Routing {0} messages to {1} via {2}", outgoingBatches.Count, entity.Path, routingOptions.ViaEntityPath); } else { Logger.DebugFormat("Routing {0} messages to {1}", outgoingBatches.Count, entity.Path); } // don't use via on fallback, not supported across namespaces var fallbacks = passiveNamespaces.Select(n => senders.Get(entity.Path, null, n.Alias)).ToList(); var ns = entity.Namespace; // only use via if the destination and via namespace are the same var via = routingOptions.SendVia && ns.ConnectionString == routingOptions.ViaConnectionString ? routingOptions.ViaEntityPath : null; var suppressTransaction = via == null; var messageSender = senders.Get(entity.Path, via, ns.Alias); routingOptions.DestinationEntityPath = entity.Path; routingOptions.DestinationNamespace = ns; var brokeredMessages = outgoingMessageConverter.Convert(outgoingBatches, routingOptions).ToList(); pendingSends.Add(RouteOutBatchesWithFallbackAndLogExceptionsAsync(messageSender, fallbacks, brokeredMessages, suppressTransaction)); } return(Task.WhenAll(pendingSends)); }
RoutingOptionsInternal GetRoutingOptions(ReceiveContextInternal receiveContext, DispatchConsistency consistency) { var sendVia = false; var context = receiveContext as BrokeredMessageReceiveContextInternal; if (context?.Recovering == false) // avoid send via when recovering to prevent error message from rolling back { sendVia = sendViaFromConfiguration & transportTypeIsNetMessaging; sendVia &= consistency != DispatchConsistency.Isolated; } return(new RoutingOptionsInternal { SendVia = sendVia, ViaEntityPath = GetViaEntityPathFor(context?.Entity), ViaConnectionString = context?.Entity.Namespace.ConnectionString, ViaPartitionKey = context?.IncomingBrokeredMessage.PartitionKey }); }
public Task RouteBatches(IEnumerable <BatchInternal> outgoingBatches, ReceiveContextInternal context, DispatchConsistency consistency) { var pendingBatches = new List <Task>(); foreach (var batch in outgoingBatches) { pendingBatches.Add(RouteBatch(batch, context as BrokeredMessageReceiveContextInternal, consistency)); } return(Task.WhenAll(pendingBatches)); }
static TransportOperation CreateTransportOperation(string id, string destination, DispatchConsistency consistency) { return(new TransportOperation( new OutgoingMessage(id, new Dictionary <string, string>(), new byte[0]), new UnicastAddressTag(destination), requiredDispatchConsistency: consistency )); }
public async Task Outgoing_operations_are_stored_atomically(Type contextProviderType, DispatchConsistency dispatchConsistency) { using (var contextProvider = CreateContext(contextProviderType, sqlConnectionFactory)) { var invalidOperations = new TransportOperations( CreateTransportOperation(id: "3", destination: ValidAddress, consistency: dispatchConsistency), CreateTransportOperation(id: "4", destination: InvalidAddress, consistency: dispatchConsistency) ); Assert.ThrowsAsync(Is.AssignableTo <Exception>(), async() => { await dispatcher.Dispatch(invalidOperations, contextProvider.TransportTransaction); contextProvider.Complete(); }); } var messagesSent = await purger.Purge(queue); Assert.AreEqual(0, messagesSent); }
public async Task Outgoing_operations_are_stored_in_destination_queue(Type contextProviderType, DispatchConsistency dispatchConsistency) { using (var contextProvider = CreateContext(contextProviderType, sqlConnectionFactory)) { var operations = new TransportOperations( CreateTransportOperation(id: "1", destination: ValidAddress, consistency: dispatchConsistency), CreateTransportOperation(id: "2", destination: ValidAddress, consistency: dispatchConsistency) ); await dispatcher.Dispatch(operations, contextProvider.TransportTransaction); contextProvider.Complete(); var messagesSent = await purger.Purge(queue); Assert.AreEqual(2, messagesSent); } }
static TransportOperation CreateTransportOperations(string messageId, string destination, DispatchConsistency dispatchConsistency = DispatchConsistency.Default) { return(new TransportOperation(new OutgoingMessage(messageId, new Dictionary <string, string>(), new byte[0]), new UnicastAddressTag(destination), dispatchConsistency)); }
bool IsCombiningTimeToBeReceivedWithTransactions(TransportTransaction transaction, DispatchConsistency requiredDispatchConsistency, List <DeliveryConstraint> deliveryConstraints) { if (!settings.UseTransactionalQueues) { return(false); } if (requiredDispatchConsistency == DispatchConsistency.Isolated) { return(false); } DiscardIfNotReceivedBefore discardIfNotReceivedBefore; var timeToBeReceivedRequested = deliveryConstraints.TryGet(out discardIfNotReceivedBefore) && discardIfNotReceivedBefore.MaxTime < MessageQueue.InfiniteTimeout; if (!timeToBeReceivedRequested) { return(false); } if (Transaction.Current != null) { return(true); } MessageQueueTransaction activeReceiveTransaction; return(TryGetNativeTransaction(transaction, out activeReceiveTransaction)); }
TransactionScope CreateTransactionScope(DispatchConsistency dispatchConsistency, bool shouldSuppressTransaction) { return(dispatchConsistency == DispatchConsistency.Isolated || shouldSuppressTransaction ? new TransactionScope(TransactionScopeOption.Suppress, TransactionScopeAsyncFlowOption.Enabled) : null); }
async Task DispatchWithTransactionScopeIfRequired(IList <Batch> toBeDispatchedOnComplete, BrokeredMessageReceiveContext context, DispatchConsistency consistency) { if (context.CancellationToken.IsCancellationRequested || !toBeDispatchedOnComplete.Any()) { return; } await routeOutgoingBatches.RouteBatches(toBeDispatchedOnComplete, context, consistency).ConfigureAwait(false); }
Task DeduplicateAndDispatch(TransportOperations operations, Func <List <UnicastTransportOperation>, Task> dispatchMethod, DispatchConsistency dispatchConsistency) { var operationsToDispatch = operations.UnicastTransportOperations .Where(o => o.RequiredDispatchConsistency == dispatchConsistency) .GroupBy(o => new DeduplicationKey(o.Message.MessageId, addressTranslator.Parse(o.Destination).Address)) .Select(g => g.First()) .ToList(); return(dispatchMethod(operationsToDispatch)); }
bool IsCombiningTimeToBeReceivedWithTransactions(TransportTransaction transaction, DispatchConsistency requiredDispatchConsistency, List<DeliveryConstraint> deliveryConstraints) { if (!settings.UseTransactionalQueues) { return false; } if (requiredDispatchConsistency == DispatchConsistency.Isolated) { return false; } DiscardIfNotReceivedBefore discardIfNotReceivedBefore; var timeToBeReceivedRequested = deliveryConstraints.TryGet(out discardIfNotReceivedBefore) && discardIfNotReceivedBefore.MaxTime < MessageQueue.InfiniteTimeout; if (!timeToBeReceivedRequested) { return false; } if (Transaction.Current != null) { return true; } MessageQueueTransaction activeReceiveTransaction; return TryGetNativeTransaction(transaction, out activeReceiveTransaction); }