예제 #1
0
        public override TransportReceiveInfrastructure ConfigureReceiveInfrastructure()
        {
            new CheckMachineNameForComplianceWithDtcLimitation().Check();

            MsmqScopeOptions scopeOptions;

            if (!settings.TryGet(out scopeOptions))
            {
                scopeOptions = new MsmqScopeOptions();
            }

            var msmqSettings = settings.Get <MsmqSettings>();

            return(new TransportReceiveInfrastructure(
                       () => new MessagePump(guarantee => SelectReceiveStrategy(guarantee, scopeOptions.TransactionOptions)),
                       () => new MsmqQueueCreator(msmqSettings.UseTransactionalQueues),
                       () =>
            {
                var bindings = settings.Get <QueueBindings>();

                foreach (var address in bindings.ReceivingAddresses)
                {
                    QueuePermissions.CheckQueue(address);
                }
                return Task.FromResult(StartupCheckResult.Success);
            }));
        }
예제 #2
0
        public override TransportSendInfrastructure ConfigureSendInfrastructure()
        {
            new CheckMachineNameForComplianceWithDtcLimitation().Check();

            Func <IReadOnlyDictionary <string, string>, string> getMessageLabel;

            settings.TryGet("Msmq.GetMessageLabel", out getMessageLabel);

            Func <IReadOnlyDictionary <string, string>, string> messageLabelGenerator;

            if (!settings.TryGet("msmqLabelGenerator", out messageLabelGenerator))
            {
                messageLabelGenerator = headers => string.Empty;
            }

            var msmqSettings = settings.Get <MsmqSettings>();

            return(new TransportSendInfrastructure(
                       () => new MsmqMessageDispatcher(msmqSettings, messageLabelGenerator),
                       () =>
            {
                var bindings = settings.Get <QueueBindings>();

                foreach (var address in bindings.SendingAddresses)
                {
                    QueuePermissions.CheckQueue(address);
                }

                var result = new MsmqTimeToBeReceivedOverrideCheck(settings).CheckTimeToBeReceivedOverrides();
                return Task.FromResult(result);
            }));
        }
예제 #3
0
        void CreateQueueIfNecessary(string address, string identity)
        {
            if (address == null)
            {
                return;
            }

            var msmqAddress = MsmqAddress.Parse(address);

            Logger.Debug($"Creating '{address}' if needed.");

            MessageQueue queue;

            if (MsmqUtilities.TryOpenQueue(msmqAddress, out queue) || MsmqUtilities.TryCreateQueue(msmqAddress, identity, settings.UseTransactionalQueues, out queue))
            {
                using (queue)
                {
                    Logger.Debug("Setting queue permissions.");

                    try
                    {
                        QueuePermissions.SetPermissionsForQueue(queue, identity);
                    }
                    catch (MessageQueueException ex)
                    {
                        Logger.Error($"Unable to set permissions for queue {queue.QueueName}", ex);
                    }
                }
            }
        }
예제 #4
0
        void CreateQueueIfNecessary(string address, string identity)
        {
            var msmqAddress = MsmqAddress.Parse(address);

            Logger.Debug($"Creating '{address}' if needed.");

            if (msmqAddress.IsRemote)
            {
                Logger.Info($"'{address}' is a remote queue and won't be created");
                return;
            }

            var queuePath = msmqAddress.PathWithoutPrefix;

            if (MessageQueue.Exists(queuePath))
            {
                Logger.Debug($"'{address}' already exists");
                return;
            }

            try
            {
                using (var queue = MessageQueue.Create(queuePath, useTransactionalQueues))
                {
                    try
                    {
                        Logger.Debug("Setting queue permissions.");

                        QueuePermissions.SetPermissionsForQueue(queue, identity);
                    }
                    catch (MessageQueueException ex)
                    {
                        Logger.Error($"Unable to set permissions for queue {queue.QueueName}", ex);
                    }
                }
            }
            catch (MessageQueueException ex)
            {
                if (ex.MessageQueueErrorCode == MessageQueueErrorCode.QueueExists)
                {
                    //Solve the race condition problem when multiple endpoints try to create same queue (e.g. error queue).
                    return;
                }

                Logger.Error($"Could not create queue {msmqAddress}. Processing will still continue.", ex);
            }
        }
        /// <inheritdoc />
        public override Task <TransportInfrastructure> Initialize(HostSettings hostSettings, ReceiveSettings[] receivers, string[] sendingAddresses, CancellationToken cancellationToken = default)
        {
            Guard.AgainstNull(nameof(hostSettings), hostSettings);
            Guard.AgainstNull(nameof(receivers), receivers);
            Guard.AgainstNull(nameof(sendingAddresses), sendingAddresses);

            CheckMachineNameForCompliance.Check();
            ValidateIfDtcIsAvailable();

            if (hostSettings.CoreSettings != null)
            {
                // enforce an explicitly configured error queue when using MSMQ transport with NServiceBus
                if (receivers.Length > 0 && !hostSettings.CoreSettings.TryGetExplicitlyConfiguredErrorQueueAddress(out _))
                {
                    throw new Exception("Faults forwarding requires an error queue to be specified using 'EndpointConfiguration.SendFailedMessagesTo()'");
                }

                bool outBoxRunning = hostSettings.CoreSettings.IsFeatureActive(typeof(Features.Outbox));
                if (hostSettings.CoreSettings.TryGetAuditMessageExpiration(out var auditMessageExpiration))
                {
                    TimeToBeReceivedOverrideChecker.Check(
                        TransportTransactionMode != TransportTransactionMode.None,
                        outBoxRunning,
                        auditMessageExpiration > TimeSpan.Zero);
                }

                if (CreateQueuesForUser == null)
                {
                    // try to use the configured installer user in Core:
                    CreateQueuesForUser = hostSettings.CoreSettings.GetOrDefault <string>("Installers.UserName");
                }
            }

            if (hostSettings.SetupInfrastructure && CreateQueues)
            {
                var installerUser  = GetInstallationUserName();
                var queueCreator   = new MsmqQueueCreator(UseTransactionalQueues, installerUser);
                var queuesToCreate = receivers
                                     .Select(r => r.ReceiveAddress)
                                     .Concat(sendingAddresses)
                                     .ToArray();
                queueCreator.CreateQueueIfNecessary(queuesToCreate);
            }

            foreach (var address in sendingAddresses)
            {
                QueuePermissions.CheckQueue(address);
            }

            hostSettings.StartupDiagnostic.Add("NServiceBus.Transport.MSMQ", new
            {
                ExecuteInstaller = CreateQueues,
                UseDeadLetterQueue,
                UseConnectionCache,
                UseTransactionalQueues,
                UseJournalQueue,
                UseDeadLetterQueueForMessagesWithTimeToBeReceived,
                TimeToReachQueue = GetFormattedTimeToReachQueue(TimeToReachQueue)
            });

            var msmqTransportInfrastructure = new MsmqTransportInfrastructure(this);

            msmqTransportInfrastructure.SetupReceivers(receivers, hostSettings.CriticalErrorAction);

            return(Task.FromResult <TransportInfrastructure>(msmqTransportInfrastructure));
        }
        /// <inheritdoc />
        public override async Task <TransportInfrastructure> Initialize(HostSettings hostSettings, ReceiveSettings[] receivers, string[] sendingAddresses, CancellationToken cancellationToken = default)
        {
            Guard.AgainstNull(nameof(hostSettings), hostSettings);
            Guard.AgainstNull(nameof(receivers), receivers);
            Guard.AgainstNull(nameof(sendingAddresses), sendingAddresses);

            CheckMachineNameForCompliance.Check();
            ValidateIfDtcIsAvailable();

            var queuesToCreate = new HashSet <string>(sendingAddresses);

            var requiresDelayedDelivery = DelayedDelivery != null;

            string      timeoutsErrorQueue         = null;
            MessagePump delayedDeliveryMessagePump = null;


            if (requiresDelayedDelivery)
            {
                QueueAddress timeoutsQueue;
                if (receivers.Length > 0)
                {
                    var mainReceiver = receivers[0];
                    timeoutsQueue      = new QueueAddress(mainReceiver.ReceiveAddress.BaseAddress, qualifier: TimeoutsQueueQualifier);
                    timeoutsErrorQueue = mainReceiver.ErrorQueue;
                }
                else
                {
                    if (hostSettings.CoreSettings != null)
                    {
                        if (!hostSettings.CoreSettings.TryGetExplicitlyConfiguredErrorQueueAddress(out var coreErrorQueue))
                        {
                            throw new Exception("Delayed delivery requires an error queue to be specified using 'EndpointConfiguration.SendFailedMessagesTo()'");
                        }

                        timeoutsErrorQueue = coreErrorQueue;
                        timeoutsQueue      = new QueueAddress(hostSettings.Name, qualifier: TimeoutsQueueQualifier); //Use name of the endpoint as the timeouts queue name.
                    }
                    else
                    {
                        throw new Exception("Timeouts are not supported for send-only configurations outside of an NServiceBus endpoint.");
                    }
                }

                delayedDeliveryMessagePump = new MessagePump(mode => SelectReceiveStrategy(mode, TransactionScopeOptions.TransactionOptions),
                                                             MessageEnumeratorTimeout, TransportTransactionMode, false, hostSettings.CriticalErrorAction,
                                                             new ReceiveSettings("DelayedDelivery", timeoutsQueue, false, false, timeoutsErrorQueue));

                queuesToCreate.Add(delayedDeliveryMessagePump.ReceiveAddress);
                queuesToCreate.Add(timeoutsErrorQueue);
            }

            var messageReceivers = CreateReceivers(receivers, hostSettings.CriticalErrorAction, queuesToCreate);

            var dispatcher = new MsmqMessageDispatcher(this, delayedDeliveryMessagePump?.ReceiveAddress, OnSendCallbackForTesting);

            if (hostSettings.CoreSettings != null)
            {
                // enforce an explicitly configured error queue when using MSMQ transport with NServiceBus
                if (receivers.Length > 0 && !hostSettings.CoreSettings.TryGetExplicitlyConfiguredErrorQueueAddress(out _))
                {
                    throw new Exception("Faults forwarding requires an error queue to be specified using 'EndpointConfiguration.SendFailedMessagesTo()'");
                }

                bool outBoxRunning = hostSettings.CoreSettings.IsFeatureActive(typeof(Features.Outbox));
                if (hostSettings.CoreSettings.TryGetAuditMessageExpiration(out var auditMessageExpiration))
                {
                    TimeToBeReceivedOverrideChecker.Check(
                        TransportTransactionMode != TransportTransactionMode.None,
                        outBoxRunning,
                        auditMessageExpiration > TimeSpan.Zero);
                }

                if (CreateQueuesForUser == null)
                {
                    // try to use the configured installer user in Core:
                    CreateQueuesForUser = hostSettings.CoreSettings.GetOrDefault <string>("Installers.UserName");
                }
            }

            if (hostSettings.SetupInfrastructure && CreateQueues)
            {
                var installerUser = GetInstallationUserName();
                var queueCreator  = new MsmqQueueCreator(UseTransactionalQueues, installerUser);

                if (requiresDelayedDelivery)
                {
                    await DelayedDelivery.DelayedMessageStore.Initialize(hostSettings.Name, TransportTransactionMode, cancellationToken).ConfigureAwait(false);
                }

                queueCreator.CreateQueueIfNecessary(queuesToCreate);
            }

            foreach (var address in sendingAddresses.Concat(messageReceivers.Select(r => r.Value.ReceiveAddress)))
            {
                QueuePermissions.CheckQueue(address);
            }

            DelayedDeliveryPump delayedDeliveryPump = null;

            if (requiresDelayedDelivery)
            {
                QueuePermissions.CheckQueue(delayedDeliveryMessagePump.ReceiveAddress);
                QueuePermissions.CheckQueue(timeoutsErrorQueue);

                var staticFaultMetadata = new Dictionary <string, string>
                {
                    { Headers.ProcessingMachine, RuntimeEnvironment.MachineName },
                    { Headers.ProcessingEndpoint, hostSettings.Name },
                    { Headers.HostDisplayName, hostSettings.HostDisplayName }
                };

                var dueDelayedMessagePoller = new DueDelayedMessagePoller(dispatcher, DelayedDelivery.DelayedMessageStore, DelayedDelivery.NumberOfRetries, hostSettings.CriticalErrorAction, timeoutsErrorQueue, staticFaultMetadata, TransportTransactionMode,
                                                                          DelayedDelivery.TimeToTriggerFetchCircuitBreaker,
                                                                          DelayedDelivery.TimeToTriggerDispatchCircuitBreaker,
                                                                          DelayedDelivery.MaximumRecoveryFailuresPerSecond,
                                                                          delayedDeliveryMessagePump.ReceiveAddress);

                delayedDeliveryPump = new DelayedDeliveryPump(dispatcher, dueDelayedMessagePoller, DelayedDelivery.DelayedMessageStore, delayedDeliveryMessagePump, timeoutsErrorQueue, DelayedDelivery.NumberOfRetries, hostSettings.CriticalErrorAction, DelayedDelivery.TimeToTriggerStoreCircuitBreaker, staticFaultMetadata, TransportTransactionMode);
            }

            hostSettings.StartupDiagnostic.Add("NServiceBus.Transport.MSMQ", new
            {
                ExecuteInstaller = CreateQueues,
                UseDeadLetterQueue,
                UseConnectionCache,
                UseTransactionalQueues,
                UseJournalQueue,
                UseDeadLetterQueueForMessagesWithTimeToBeReceived,
                TimeToReachQueue   = GetFormattedTimeToReachQueue(TimeToReachQueue),
                TimeoutQueue       = delayedDeliveryMessagePump?.ReceiveAddress,
                TimeoutStorageType = DelayedDelivery?.DelayedMessageStore?.GetType(),
            });

            var infrastructure = new MsmqTransportInfrastructure(messageReceivers, dispatcher, delayedDeliveryPump);
            await infrastructure.Start(cancellationToken).ConfigureAwait(false);

            return(infrastructure);
        }