public Task StartAsync(CancellationToken stoppingToken)
        {
            _logger.LogInformation("AzureServiceBusMessagePump running. Endpoint: {EndpointName}", _endpoint.Name);

            if (!_endpoint.Settings.IsReader)
            {
                return(Task.CompletedTask);
            }

            _receiver = AzureServiceBusClientCache.GetReceiver(_endpoint.Settings.ConnectionString);
            _receiver.RegisterMessageHandler(async(message, token) =>
            {
                if (token.IsCancellationRequested)
                {
                    return;
                }

                await _handleMessage(new RecoverabilityContext(_receiver, _endpoint, message), token);
            },
                                             new MessageHandlerOptions((args) =>
            {
                _logger.LogError(args.Exception, "AzureServiceBusMessagePump encountered an unhandled exception while handling a message. Endpoint: {EndpointName}", _endpoint.Name);
                return(Task.CompletedTask);
            })
            {
                MaxConcurrentCalls = _maxConcurrentHandlers, //# concurrent handlers allowed
                AutoComplete       = false,
                //MaxAutoRenewDuration = TimeSpan.FromSeconds(20)
            });

            return(Task.CompletedTask);
        }
        public async Task Recover(RecoverabilityContext context)
        {
            var sender = AzureServiceBusClientCache.GetSender(context.Endpoint.Settings.ConnectionString);
            var count  = _getRecoveryCount(context.Message, context);

            var retryMessage = context.Message.Clone();

            retryMessage.MessageId = Guid.NewGuid().ToString();
            retryMessage.UserProperties.Add("OriginalMessageId", context.Message.MessageId);
            retryMessage.UserProperties.Add("RecoveryCount", ++count);

            await sender.ScheduleMessageAsync(
                retryMessage,
                this._retryStrategy.GetNextDateUtc(++count)
                );

            //complete the original message - we've already scheduled a clone
            await _completeImmediateRetryPolicy.ExecuteAsync(() =>
                                                             context.Receiver.CompleteAsync(context.Message.SystemProperties.LockToken)
                                                             );
        }
        protected Task _dispatch(string messageTypeIdentifier, byte[] messageBody, IEndpoint endpoint, MessageMetaData meta = null)
        {
            var message = new Message(messageBody);
            var sender  = AzureServiceBusClientCache.GetSender(endpoint.Settings.ConnectionString);

            _metaDataMapper.ApplyMetaData(message, meta, messageTypeIdentifier);

            DateTime?scheduleAtUtc = null;

            if (meta != null && meta.DispatchDelay.HasValue)
            {
                //var baseDate = meta.CreatedAtUtc.HasValue ? meta.CreatedAtUtc.Value : DateTime.UtcNow;
                var baseDate = DateTime.UtcNow;
                scheduleAtUtc = baseDate.Add(meta.DispatchDelay.Value);
            }
            if (scheduleAtUtc.HasValue)// && scheduleAtUtc > DateTime.UtcNow.AddMilliseconds(400))
            {
                return(sender.ScheduleMessageAsync(message, scheduleAtUtc.Value));
            }
            return(sender.SendAsync(message));
        }
        public async Task Recover(RecoverabilityContext context) // int timesQueued, Endpoint endpoint, IMessageReceiver receiver, Message controlMessage = null, string description = null, Exception exc = null)
        {
            if (IsControlMessage(context.Message))               //never try to reschedule the control messages themselves
            {
                return;
            }

            var count = context.TempData.ContainsKey("ControlMessageContent") ?
                        ((RecoverabilityControlMessage)context.TempData["ControlMessageContent"]).RecoveryCount
                : 0;
            var sender       = AzureServiceBusClientCache.GetSender(context.Endpoint.Settings.ConnectionString);
            var retryMessage = new RecoverabilityControlMessage(context.Message.SystemProperties.SequenceNumber, ++count);

            //schedule a special control message to be delivered in the future to tell the the deferred message to be retrieved and re processed
            await sender.ScheduleMessageAsync(
                _createServiceBusMessage(retryMessage),
                this._retryStrategy.GetNextDateUtc(retryMessage.RecoveryCount)
                );

            //defer the current message / first time through
            if (!context.TempData.ContainsKey("ControlMessage"))
            {
                await context.Receiver.DeferAsync(context.Message.SystemProperties.LockToken);
            }
            else //already deferred. complete the control message / we just sent a new one above
            {
                await _completeImmediateRetryPolicy.ExecuteAsync(() =>
                                                                 context.Receiver.CompleteAsync(((Message)context.TempData["ControlMessage"]).SystemProperties.LockToken)
                                                                 );

                //release the lock on the current deferred message
                await _completeImmediateRetryPolicy.ExecuteAsync(() =>
                                                                 context.Receiver.AbandonAsync(context.Message.SystemProperties.LockToken)
                                                                 );
            }
        }
 public Task StopAsync()
 {
     _logger.LogInformation("AzureServiceBusMessagePump stopping. Endpoint: {EndpointName}", _endpoint.Name);
     return(AzureServiceBusClientCache.CloseReceiver(_receiver));
 }