IAsyncResult SendMessage(ConnectionImpl connection, Func <BrokeredMessage> createMessage,
                                 int sendNumber, AsyncCallback cb, object state)
        {
            var msg = createMessage();

            msg.Properties[NumberOfRetries] = sendNumber - 1;

            Address.LogBeginSend(msg.MessageId);

            Interlocked.Increment(ref _messagesInFlight);

            return(connection.MessageSender.BeginSend(msg,
                                                      cb, new StateHolder(connection.MessageSender, msg)));
        }
Exemple #2
0
        ConnectionHandler <ConnectionImpl> GetConnection([NotNull] AzureServiceBusEndpointAddress address)
        {
            if (address == null)
            {
                throw new ArgumentNullException("address");
            }
            _logger.DebugFormat("get connection( address:'{0}' )", address);

            return(_connCache.Retrieve(address.Uri, () =>
            {
                var connection = new ConnectionImpl(address);
                var connectionHandler = new ConnectionHandlerImpl <ConnectionImpl>(connection);

                return connectionHandler;
            }));
        }
		ConnectionHandler<ConnectionImpl> GetConnection([NotNull] AzureServiceBusEndpointAddress address)
		{
			if (address == null) throw new ArgumentNullException("address");
			_logger.DebugFormat("get connection( address:'{0}' )", address);

			return _connCache.Retrieve(address.Uri, () =>
				{
					var connection = new ConnectionImpl(address);
					var connectionHandler = new ConnectionHandlerImpl<ConnectionImpl>(connection);

					return connectionHandler;
				});
		}
		IAsyncResult SendMessage(ConnectionImpl connection, Func<BrokeredMessage> createMessage, 
			int sendNumber, AsyncCallback cb, object state)
		{
			var msg = createMessage();

			msg.Properties[NumberOfRetries] = sendNumber - 1;

			Address.LogBeginSend(msg.MessageId);

			Interlocked.Increment(ref _messagesInFlight);

			return connection.MessageSender.BeginSend(msg,
				cb, new StateHolder(connection.MessageSender, msg));
		}
		// call only if first time gotten server busy exception
		void RetryLoop(ConnectionImpl connection, string messageId, int sendNumber, Func<BrokeredMessage> createMessage)
		{
			Address.LogSendRetryScheduled(messageId, _messagesInFlight, Interlocked.Increment(ref _sleeping));

			// exception tells me to wait 10 seconds before retrying, so let's sleep 1 second instead,
			// just 2,600,000,000 CPU cycles
			Thread.Sleep(1.Seconds());

			Interlocked.Decrement(ref _sleeping);

			_logger.WarnFormat("scheduling retry no. {0} for msg #{1} ", sendNumber, messageId);

			// push all pending retries onto the sending operation
			TrySendMessage(connection, createMessage, sendNumber + 1);
		}
		void TrySendMessage(ConnectionImpl connection, Func<BrokeredMessage> createMessage, int sendNumber)
		{
			var msg = createMessage();
			var messageId = msg.MessageId;
			var sender = connection.MessageSender;

			msg.Properties[NumberOfRetries] = sendNumber - 1;

			Address.LogBeginSend(msg.MessageId);

			Interlocked.Increment(ref _messagesInFlight);

			connection.MessageSender.BeginSend(msg, ar =>
				{
					Exception caught = null;

					// if the queue is deleted in the middle of things here, then I can't recover
					// at the moment; I have to extend the connection handler with an asynchronous
					// API to let it re-initialize the queue and hence maybe even the full transport...

					// So if I get MessagingEntityNotFoundException, I'm toast with this code: 
					// don't delete queues in use.

					Interlocked.Decrement(ref _messagesInFlight);

					try
					{
						sender.EndSend(ar);
						Address.LogEndSend(msg.MessageId);
					}
					// see: http://msdn.microsoft.com/en-us/library/windowsazure/hh418082.aspx
					catch (ServerBusyException ex)
					{
						// "Service is not able to process the request at this time."
						_logger.Warn(string.Format("service bus busy, retrying for msg #{0}", messageId), ex);
						caught = ex;
					}
					catch (MessagingCommunicationException ex)
					{
						// "Client is not able to establish a connection to the Service Bus."
						_logger.Warn(string.Format("service bus sad, retrying for msg #{0}", messageId), ex);
						caught = ex;
					}
					catch (UnauthorizedAccessException ex)
					{
						_logger.Warn(string.Format("ACS confused, retrying for msg #{0}", messageId), ex);
						caught = ex;
					}
					catch(TimeoutException ex)
					{
						// "...could not acquire a token, the token is invalid, or the token does not contain the claims required to perform the operation."
						_logger.Info(string.Format("server timed out for msg #{0}", messageId), ex);
						caught = ex;
					}
					catch (Exception ex)
					{
						// this is really bad, we are now losing a message, but we can't recover in any way
						_logger.Fatal(string.Format("other exception for msg #{0} - giving up", messageId), ex);
						// intentionally not setting 'caught' variable
					}

					// always dispose the message; it's only good once
					msg.Dispose();

					// success or deadly exception (last catch), so we don't retry
					if (caught == null)
						return;
					
					RetryLoop(connection, messageId, sendNumber, createMessage);
				}, null);
		}