public Task Init(Func <MessageContext, Task> onMessage, Func <ErrorContext, Task <ErrorHandleResult> > onError, CriticalError criticalError, PushSettings settings)
        {
            peekCircuitBreaker    = new RepeatedFailuresOverTimeCircuitBreaker("MsmqPeek", TimeSpan.FromSeconds(30), ex => criticalError.Raise("Failed to peek " + settings.InputQueue, ex));
            receiveCircuitBreaker = new RepeatedFailuresOverTimeCircuitBreaker("MsmqReceive", TimeSpan.FromSeconds(30), ex => criticalError.Raise("Failed to receive from " + settings.InputQueue, ex));

            var inputAddress = MsmqAddress.Parse(settings.InputQueue);
            var errorAddress = MsmqAddress.Parse(settings.ErrorQueue);

            if (!string.Equals(inputAddress.Machine, RuntimeEnvironment.MachineName, StringComparison.OrdinalIgnoreCase))
            {
                throw new Exception($"MSMQ Dequeuing can only run against the local machine. Invalid inputQueue name '{settings.InputQueue}'.");
            }

            inputQueue = new MessageQueue(inputAddress.FullPath, false, true, QueueAccessMode.Receive);
            errorQueue = new MessageQueue(errorAddress.FullPath, false, true, QueueAccessMode.Send);

            if (settings.RequiredTransactionMode != TransportTransactionMode.None && !QueueIsTransactional())
            {
                throw new ArgumentException($"Queue must be transactional if you configure the endpoint to be transactional ({settings.InputQueue}).");
            }

            inputQueue.MessageReadPropertyFilter = DefaultReadPropertyFilter;

            if (settings.PurgeOnStartup)
            {
                inputQueue.Purge();
            }

            receiveStrategy = receiveStrategyFactory(settings.RequiredTransactionMode);

            receiveStrategy.Init(inputQueue, errorQueue, onMessage, onError, criticalError);

            return(TaskEx.CompletedTask);
        }
        public Task StartReceive(CancellationToken cancellationToken = default)
        {
            MessageQueue.ClearConnectionCache();

            messagePumpCancellationTokenSource       = new CancellationTokenSource();
            messageProcessingCancellationTokenSource = new CancellationTokenSource();

            peekCircuitBreaker = new RepeatedFailuresOverTimeCircuitBreaker("MsmqPeek", TimeSpan.FromSeconds(30),
                                                                            ex => criticalErrorAction("Failed to peek " + receiveSettings.ReceiveAddress, ex, messageProcessingCancellationTokenSource.Token));

            receiveCircuitBreaker = new RepeatedFailuresOverTimeCircuitBreaker("MsmqReceive", TimeSpan.FromSeconds(30),
                                                                               ex => criticalErrorAction("Failed to receive from " + receiveSettings.ReceiveAddress, ex, messageProcessingCancellationTokenSource.Token));

            // LongRunning is useless combined with async/await
            messagePumpTask = Task.Run(() => PumpMessages(), cancellationToken);

            return(Task.CompletedTask);
        }
        public Task StartReceive(CancellationToken cancellationToken = default)
        {
            MessageQueue.ClearConnectionCache();

            messagePumpCancellationTokenSource       = new CancellationTokenSource();
            messageProcessingCancellationTokenSource = new CancellationTokenSource();

            peekCircuitBreaker = new RepeatedFailuresOverTimeCircuitBreaker("MsmqPeek", TimeSpan.FromSeconds(30),
                                                                            ex => criticalErrorAction("Failed to peek " + receiveSettings.ReceiveAddress, ex, messageProcessingCancellationTokenSource.Token));

            receiveCircuitBreaker = new RepeatedFailuresOverTimeCircuitBreaker("MsmqReceive", TimeSpan.FromSeconds(30),
                                                                               ex => criticalErrorAction("Failed to receive from " + receiveSettings.ReceiveAddress, ex, messageProcessingCancellationTokenSource.Token));

            // Task.Run() so the call returns immediately instead of waiting for the first await or return down the call stack
            // LongRunning is useless combined with async/await
            messagePumpTask = Task.Run(() => PumpMessagesAndSwallowExceptions(messagePumpCancellationTokenSource.Token), CancellationToken.None);

            return(Task.CompletedTask);
        }