public async Task ConfigureReceiveInfrastructure(ReceiveSettings[] receiveSettings, string[] sendingAddresses, CancellationToken cancellationToken = default) { var transactionOptions = transport.TransactionScope.TransactionOptions; diagnostics.Add("NServiceBus.Transport.SqlServer.Transactions", new { TransactionMode = transport.TransportTransactionMode, transactionOptions.IsolationLevel, transactionOptions.Timeout }); diagnostics.Add("NServiceBus.Transport.SqlServer.CircuitBreaker", new { TimeToWaitBeforeTriggering = transport.TimeToWaitBeforeTriggeringCircuitBreaker }); var queuePeekerOptions = transport.QueuePeeker; var createMessageBodyComputedColumn = transport.CreateMessageBodyComputedColumn; Func <TransportTransactionMode, ProcessStrategy> processStrategyFactory = guarantee => SelectProcessStrategy(guarantee, transactionOptions, connectionFactory); var queuePurger = new QueuePurger(connectionFactory); var queuePeeker = new QueuePeeker(connectionFactory, queuePeekerOptions); IExpiredMessagesPurger expiredMessagesPurger; bool validateExpiredIndex; if (transport.ExpiredMessagesPurger.PurgeOnStartup == false) { diagnostics.Add("NServiceBus.Transport.SqlServer.ExpiredMessagesPurger", new { Enabled = false, }); expiredMessagesPurger = new NoOpExpiredMessagesPurger(); validateExpiredIndex = false; } else { var purgeBatchSize = transport.ExpiredMessagesPurger.PurgeBatchSize; diagnostics.Add("NServiceBus.Transport.SqlServer.ExpiredMessagesPurger", new { Enabled = true, BatchSize = purgeBatchSize }); expiredMessagesPurger = new ExpiredMessagesPurger((_, token) => connectionFactory.OpenNewConnection(token), purgeBatchSize); validateExpiredIndex = true; } var schemaVerification = new SchemaInspector((queue, token) => connectionFactory.OpenNewConnection(token), validateExpiredIndex); var queueFactory = transport.Testing.QueueFactoryOverride ?? (queueName => new TableBasedQueue(addressTranslator.Parse(queueName).QualifiedTableName, queueName, !isEncrypted)); //Create delayed delivery infrastructure CanonicalQueueAddress delayedQueueCanonicalAddress = null; if (transport.DisableDelayedDelivery == false) { var delayedDelivery = transport.DelayedDelivery; diagnostics.Add("NServiceBus.Transport.SqlServer.DelayedDelivery", new { Native = true, Suffix = delayedDelivery.TableSuffix, Interval = delayedDelivery.ProcessingInterval, delayedDelivery.BatchSize, }); var queueAddress = new Transport.QueueAddress(hostSettings.Name, null, new Dictionary <string, string>(), delayedDelivery.TableSuffix); delayedQueueCanonicalAddress = addressTranslator.GetCanonicalForm(addressTranslator.Generate(queueAddress)); //For backwards-compatibility with previous version of the seam and endpoints that have delayed //delivery infrastructure, we assume that the first receiver address matches main input queue address //from version 7 of Core. For raw usages this will still work but delayed-delivery messages //might be moved to arbitrary picked receiver var mainReceiverInputQueueAddress = receiveSettings[0].ReceiveAddress; var inputQueueTable = addressTranslator.Parse(mainReceiverInputQueueAddress).QualifiedTableName; var delayedMessageTable = new DelayedMessageTable(delayedQueueCanonicalAddress.QualifiedTableName, inputQueueTable); //Allows dispatcher to store messages in the delayed store delayedMessageStore = delayedMessageTable; dueDelayedMessageProcessor = new DueDelayedMessageProcessor(delayedMessageTable, connectionFactory, delayedDelivery.ProcessingInterval, delayedDelivery.BatchSize, transport.TimeToWaitBeforeTriggeringCircuitBreaker, hostSettings); } Receivers = receiveSettings.Select(s => { ISubscriptionManager subscriptionManager = transport.SupportsPublishSubscribe ? (ISubscriptionManager) new SubscriptionManager(subscriptionStore, hostSettings.Name, s.ReceiveAddress) : new NoOpSubscriptionManager(); return(new MessageReceiver(transport, s, hostSettings, processStrategyFactory, queueFactory, queuePurger, expiredMessagesPurger, queuePeeker, queuePeekerOptions, schemaVerification, transport.TimeToWaitBeforeTriggeringCircuitBreaker, subscriptionManager)); }).ToDictionary <MessageReceiver, string, IMessageReceiver>(receiver => receiver.Id, receiver => receiver); await ValidateDatabaseAccess(transactionOptions, cancellationToken).ConfigureAwait(false); var receiveAddresses = receiveSettings.Select(r => r.ReceiveAddress).ToList(); if (hostSettings.SetupInfrastructure) { var queuesToCreate = new List <string>(); queuesToCreate.AddRange(sendingAddresses); queuesToCreate.AddRange(receiveAddresses); var queueCreator = new QueueCreator(connectionFactory, addressTranslator, createMessageBodyComputedColumn); await queueCreator.CreateQueueIfNecessary(queuesToCreate.ToArray(), delayedQueueCanonicalAddress, cancellationToken) .ConfigureAwait(false); } dueDelayedMessageProcessor?.Start(cancellationToken); transport.Testing.SendingAddresses = sendingAddresses.Select(s => addressTranslator.Parse(s).QualifiedTableName).ToArray(); transport.Testing.ReceiveAddresses = receiveAddresses.Select(r => addressTranslator.Parse(r).QualifiedTableName).ToArray(); transport.Testing.DelayedDeliveryQueue = delayedQueueCanonicalAddress?.QualifiedTableName; }
public override TransportReceiveInfrastructure ConfigureReceiveInfrastructure() { if (!settings.TryGet(out SqlScopeOptions scopeOptions)) { scopeOptions = new SqlScopeOptions(); } settings.TryGet(out TransportTransactionMode transactionMode); diagnostics.Add("NServiceBus.Transport.SqlServer.Transactions", new { TransactionMode = transactionMode, scopeOptions.TransactionOptions.IsolationLevel, scopeOptions.TransactionOptions.Timeout }); if (!settings.TryGet(SettingsKeys.TimeToWaitBeforeTriggering, out TimeSpan waitTimeCircuitBreaker)) { waitTimeCircuitBreaker = TimeSpan.FromSeconds(30); } diagnostics.Add("NServiceBus.Transport.SqlServer.CircuitBreaker", new { TimeToWaitBeforeTriggering = waitTimeCircuitBreaker }); if (!settings.TryGet(out QueuePeekerOptions queuePeekerOptions)) { queuePeekerOptions = new QueuePeekerOptions(); } var createMessageBodyComputedColumn = settings.GetOrDefault <bool>(SettingsKeys.CreateMessageBodyComputedColumn); Func <TransportTransactionMode, ReceiveStrategy> receiveStrategyFactory = guarantee => SelectReceiveStrategy(guarantee, scopeOptions.TransactionOptions, connectionFactory); var queuePurger = new QueuePurger(connectionFactory); var queuePeeker = new QueuePeeker(connectionFactory, queuePeekerOptions); IExpiredMessagesPurger expiredMessagesPurger; bool validateExpiredIndex; if (settings.GetOrDefault <bool>(SettingsKeys.PurgeEnableKey)) { diagnostics.Add("NServiceBus.Transport.SqlServer.ExpiredMessagesPurger", new { Enabled = false, }); expiredMessagesPurger = new NoOpExpiredMessagesPurger(); validateExpiredIndex = false; } else { var purgeBatchSize = settings.HasSetting(SettingsKeys.PurgeBatchSizeKey) ? settings.Get <int?>(SettingsKeys.PurgeBatchSizeKey) : null; diagnostics.Add("NServiceBus.Transport.SqlServer.ExpiredMessagesPurger", new { Enabled = true, BatchSize = purgeBatchSize }); expiredMessagesPurger = new ExpiredMessagesPurger(_ => connectionFactory.OpenNewConnection(), purgeBatchSize); validateExpiredIndex = true; } var schemaVerification = new SchemaInspector(queue => connectionFactory.OpenNewConnection(), validateExpiredIndex); Func <string, TableBasedQueue> queueFactory = queueName => new TableBasedQueue(addressTranslator.Parse(queueName).QualifiedTableName, queueName, !isEncrypted); //Create delayed delivery infrastructure CanonicalQueueAddress delayedQueueCanonicalAddress = null; if (settings.GetOrDefault <bool>(SettingsKeys.DisableDelayedDelivery) == false) { if (!settings.TryGet(SettingsKeys.DelayedDeliverySuffix, out string suffix)) { suffix = "Delayed"; } if (!settings.TryGet(SettingsKeys.DelayedDeliveryInterval, out TimeSpan interval)) { interval = TimeSpan.FromSeconds(1); } if (!settings.TryGet(SettingsKeys.DelayedDeliveryMatureBatchSize, out int matureBatchSize)) { matureBatchSize = 100; } settings.AddStartupDiagnosticsSection("NServiceBus.Transport.SqlServer.DelayedDelivery", new { Native = true, Suffix = suffix, Interval = interval, BatchSize = matureBatchSize, }); delayedQueueCanonicalAddress = GetDelayedTableAddress(suffix); var inputQueueTable = addressTranslator.Parse(ToTransportAddress(logicalAddress())).QualifiedTableName; var delayedMessageTable = new DelayedMessageTable(delayedQueueCanonicalAddress.QualifiedTableName, inputQueueTable); //Allows dispatcher to store messages in the delayed store delayedMessageStore = delayedMessageTable; dueDelayedMessageProcessor = new DueDelayedMessageProcessor(delayedMessageTable, connectionFactory, interval, matureBatchSize); } return(new TransportReceiveInfrastructure( () => new MessagePump(receiveStrategyFactory, queueFactory, queuePurger, expiredMessagesPurger, queuePeeker, queuePeekerOptions, schemaVerification, waitTimeCircuitBreaker), () => new QueueCreator(connectionFactory, addressTranslator, delayedQueueCanonicalAddress, createMessageBodyComputedColumn), () => ValidateDatabaseAccess(scopeOptions.TransactionOptions))); }