Пример #1
0
        /// <summary>
        /// Begins asynchronous processing of a single <see cref="T:MySpace.DataRelay.RelayMessage"/>.
        /// </summary>
        /// <param name="message">The <see cref="T:MySpace.DataRelay.RelayMessage"/>.</param>
        /// <param name="state">Callers can put any state they like here.</param>
        /// <param name="callback">The method to call upon completion.</param>
        /// <returns>
        /// Returns an <see cref="T:System.IAsyncResult"/>.
        /// </returns>
        public IAsyncResult BeginHandleMessage(RelayMessage message, object state, AsyncCallback callback)
        {
            if (!message.IsTwoWayMessage)
            {
                // cheat for now and just handle in messages synchronously
                // as long as the type doesn't use sync in messages then
                // we won't block on IO anyway.
                HandleMessage(message);
                return(SynchronousAsyncResult.CreateAndComplete(callback, state));
            }


            SimpleLinkedList <Node> nodes = PrepareMessage(message, false);

            Node node;

            if (nodes.Pop(out node))
            {
                var result = new AsynchronousResult <Node>((ar, n, m) =>
                {
                    n.EndHandleOutMessage(ar);
                    int allowedRetries = NodeManager.Instance.GetRetryCountForMessage(message);
                    while (message.ErrorType == RelayErrorType.NodeUnreachable && --allowedRetries >= 0)
                    {
                        if (PrepareMessage(message, true).Pop(out node))
                        {
                            node.HandleOutMessage(message);
                        }
                        else
                        {
                            message.SetError(RelayErrorType.NoNodesAvailable);
                        }
                    }
                }, node, message);
                var origCallback = callback;
                if (callback != null)
                {
                    callback = ar =>
                    {
                        result.InnerResult = ar;
                        origCallback(result);
                    };
                }
                result.InnerResult = node.BeginHandleOutMessage(message, callback, state);
                return(result);
            }
            else
            {
                message.SetError(RelayErrorType.NoNodesAvailable);
            }
            return(SynchronousAsyncResult.CreateAndComplete(callback, state));
        }
Пример #2
0
        private static void RetryHandleMessageOnError(RelayMessage message, Node node)
        {
            int         allowedRetries = NodeManager.Instance.GetRetryCountForMessage(message);
            List <Node> attemptedNodes = null;

            while (--allowedRetries >= 0 && message.IsRetryable(NodeManager.Instance.GetRelayRetryPolicyForMessage(message)))
            {
                if (attemptedNodes == null)
                {
                    attemptedNodes = new List <Node>(allowedRetries + 1);
                }

                attemptedNodes.Add(node);

                node = PrepareRetryMessage(message, attemptedNodes);
                if (node != null)
                {
                    node.HandleOutMessage(message);
                }
                else
                {
                    message.SetError(RelayErrorType.NoNodesAvailable);
                }
            }
        }
Пример #3
0
        /// <summary>
        /// Begins asynchronous processing of a single <see cref="T:MySpace.DataRelay.RelayMessage"/>.
        /// </summary>
        /// <param name="message">The <see cref="T:MySpace.DataRelay.RelayMessage"/>.</param>
        /// <param name="state">Callers can put any state they like here.</param>
        /// <param name="callback">The method to call upon completion.</param>
        /// <returns>
        /// Returns an <see cref="T:System.IAsyncResult"/>.
        /// </returns>
        public virtual IAsyncResult BeginHandleMessage(RelayMessage message, object state, AsyncCallback callback)
        {
            if (!message.IsTwoWayMessage)
            {
                // cheat for now and just handle in messages synchronously
                // as long as the type doesn't use sync in messages then
                // we won't block on IO anyway.
                HandleMessage(message);
                return(SynchronousAsyncResult.CreateAndComplete(callback, state));
            }

            LinkedListStack <Node> nodes = PrepareMessage(message);

            Node node;

            if (nodes.Pop(out node))
            {
                var result = new AsynchronousResult <Node>((ar, n, m) =>
                {
                    try
                    {
                        n.EndHandleOutMessage(ar);
                        RetryHandleMessageOnError(message, node);
                    }
                    catch (Exception ex)
                    {
                        log.Error(ex);
                    }
                }, node, message);

                var origCallback = callback;
                if (callback != null)
                {
                    callback = ar =>
                    {
                        result.InnerResult = ar;
                        origCallback(result);
                    };
                }
                result.InnerResult = node.BeginHandleOutMessage(message, callback, state);
                return(result);
            }

            message.SetError(RelayErrorType.NoNodesAvailable);

            return(SynchronousAsyncResult.CreateAndComplete(callback, state));
        }
Пример #4
0
        private static Node PrepareRetryMessage(RelayMessage message, IList <Node> attemptedNodes)
        {
            if (attemptedNodes.Count == 0)
            {
                throw new ArgumentException("PrepareRetryMessage must be called after the first attempt.", "attemptedNodes");
            }
            var node = attemptedNodes[0];

            if (node == null)
            {
                throw new ArgumentException("The first element is null.", "attemptedNodes");
            }

            node = node.GetRetryNodeFromCluster(attemptedNodes);
            message.RelayTTL++;
            message.SetError(RelayErrorType.None);
            message.ResultOutcome = RelayOutcome.NotSent;
            return(node);
        }
Пример #5
0
        /// <summary>
        ///	Performs processing on single message
        /// </summary>
        /// <exception cref="SyncRelayOperationException">
        /// When the type of an object is defined with settings
        ///		<see cref="MySpace.DataRelay.Common.Schemas.TypeSettings"></see> with
        ///		SyncInMessages=true and
        ///		ThrowOnSyncFailure=true
        ///	failed "in" executions will throw this exception
        /// </exception>
        /// <param name="message">Message to be processed</param>
        public void HandleMessage(RelayMessage message)
        {
            Node node;

            if (message.IsTwoWayMessage)
            {
                int  allowedRetries = NodeManager.Instance.GetRetryCountForMessage(message);
                bool triedBefore    = false;
                do
                {
                    if (PrepareMessage(message, triedBefore).Pop(out node))
                    {
                        triedBefore = true;
                        node.HandleOutMessage(message);
                    }
                    else
                    {
                        message.SetError(RelayErrorType.NoNodesAvailable);
                    }
                }while (message.ErrorType == RelayErrorType.NodeUnreachable && --allowedRetries >= 0);
            }
            else
            {
                SimpleLinkedList <Node> nodes                      = PrepareMessage(message, false);
                SerializedRelayMessage  serializedMessage          = new SerializedRelayMessage(message);
                SerializedRelayMessage  serializedMessageInterZone = null;

                bool messageHandled = true;                 // start with "true" so that we do not pop
                // if there are no items in "nodes"
                if (nodes.Count == 0)
                {
                    message.SetError(RelayErrorType.NoNodesAvailable);
                }
                else
                {
                    while (nodes.Pop(out node))
                    {
                        TypeSetting typeSetting = NodeManager.Instance.Config.TypeSettings.TypeSettingCollection[message.TypeId];

                        bool typesettingThrowOnSyncFailure = false;
                        bool typesettingSyncInMessages     = false;
                        if (null != typeSetting && !node.NodeCluster.MeInThisCluster)
                        {
                            typesettingSyncInMessages     = typeSetting.SyncInMessages;
                            typesettingThrowOnSyncFailure = typeSetting.ThrowOnSyncFailure;
                        }

                        if (_myNodeDefinition != null && _myNodeDefinition.Zone != node.NodeDefinition.Zone)
                        {
                            // Message needs to cross Zone bounderies
                            if (serializedMessageInterZone == null)
                            {
                                serializedMessageInterZone = new SerializedRelayMessage(RelayMessage.CreateInterZoneMessageFrom(message));
                            }

                            if (message.ResultOutcome == null)
                            {
                                message.ResultOutcome = RelayOutcome.Queued;
                            }
                            node.HandleInMessage(serializedMessageInterZone);
                        }
                        else if (typesettingSyncInMessages)
                        {
                            messageHandled = node.HandleInMessageSync(message, typesettingSyncInMessages, typesettingThrowOnSyncFailure);
                        }
                        else
                        {
                            if (message.ResultOutcome == null)
                            {
                                message.ResultOutcome = RelayOutcome.Queued;
                            }
                            node.HandleInMessage(serializedMessage);
                        }

                        if (!messageHandled)
                        {
                            throw new SyncRelayOperationException(string.Format("Node {0} failed to process message {1}\r\n", node, message));
                        }
                    }
                }
            }
        }
Пример #6
0
		/// <summary>
		/// Begins asynchronous processing of a single <see cref="T:MySpace.DataRelay.RelayMessage"/>.
		/// </summary>
		/// <param name="message">The <see cref="T:MySpace.DataRelay.RelayMessage"/>.</param>
		/// <param name="state">Callers can put any state they like here.</param>
		/// <param name="callback">The method to call upon completion.</param>
		/// <returns>
		/// Returns an <see cref="T:System.IAsyncResult"/>.
		/// </returns>
		public IAsyncResult BeginHandleMessage(RelayMessage message, object state, AsyncCallback callback)
		{
			if (!message.IsTwoWayMessage)
			{
				// cheat for now and just handle in messages synchronously
				// as long as the type doesn't use sync in messages then
				// we won't block on IO anyway.
				HandleMessage(message);
				return SynchronousAsyncResult.CreateAndComplete(callback, state);
			}

			
			SimpleLinkedList<Node> nodes = PrepareMessage(message, false);

			Node node;
			if (nodes.Pop(out node))
			{
				var result = new AsynchronousResult<Node>((ar, n, m) =>
				{
					n.EndHandleOutMessage(ar);
					int allowedRetries = NodeManager.Instance.GetRetryCountForMessage(message);
					while (message.ErrorType == RelayErrorType.NodeUnreachable && --allowedRetries >= 0)
					{
						if (PrepareMessage(message, true).Pop(out node))
						{
							node.HandleOutMessage(message);
						}
						else
						{
							message.SetError(RelayErrorType.NoNodesAvailable);
						}
					}
				}, node, message);
				var origCallback = callback;
				if (callback != null)
				{
					callback = ar =>
					{
						result.InnerResult = ar;
						origCallback(result);
					};
				}
				result.InnerResult = node.BeginHandleOutMessage(message, callback, state);
				return result;
			}
			else
			{
				message.SetError(RelayErrorType.NoNodesAvailable);
			}
			return SynchronousAsyncResult.CreateAndComplete(callback, state);
		}
Пример #7
0
		/// <summary>
		///	Performs processing on single message
		/// </summary>
		/// <exception cref="SyncRelayOperationException">
		/// When the type of an object is defined with settings
		///		<see cref="MySpace.DataRelay.Common.Schemas.TypeSettings"></see> with 
		///		SyncInMessages=true and 
		///		ThrowOnSyncFailure=true
		///	failed "in" executions will throw this exception
		/// </exception>
		/// <param name="message">Message to be processed</param>
		public void HandleMessage(RelayMessage message)
		{
			
			Node node;
			if (message.IsTwoWayMessage)
			{
				int allowedRetries = NodeManager.Instance.GetRetryCountForMessage(message);
				bool triedBefore = false;
				do
				{
					if (PrepareMessage(message, triedBefore).Pop(out node))
					{
						triedBefore = true;
						node.HandleOutMessage(message);
					}
					else
					{
						message.SetError(RelayErrorType.NoNodesAvailable);
					}
				}
				while (message.ErrorType == RelayErrorType.NodeUnreachable && --allowedRetries >= 0);
			}
			else
			{
				SimpleLinkedList<Node> nodes = PrepareMessage(message, false);
				SerializedRelayMessage serializedMessage = new SerializedRelayMessage(message);
				SerializedRelayMessage serializedMessageInterZone = null;

				bool messageHandled = true; // start with "true" so that we do not pop
				// if there are no items in "nodes"
				if (nodes.Count == 0)
				{
					message.SetError(RelayErrorType.NoNodesAvailable);
				}
				else
				{
					while (nodes.Pop(out node))
					{
						TypeSetting typeSetting = NodeManager.Instance.Config.TypeSettings.TypeSettingCollection[message.TypeId];

						bool typesettingThrowOnSyncFailure = false;
						bool typesettingSyncInMessages = false;
						if (null != typeSetting && !node.NodeCluster.MeInThisCluster)
						{
							typesettingSyncInMessages = typeSetting.SyncInMessages;
							typesettingThrowOnSyncFailure = typeSetting.ThrowOnSyncFailure;
						}

						if (_myNodeDefinition != null && _myNodeDefinition.Zone != node.NodeDefinition.Zone)
						{
							// Message needs to cross Zone bounderies
							if (serializedMessageInterZone == null)
							{
								serializedMessageInterZone = new SerializedRelayMessage(RelayMessage.CreateInterZoneMessageFrom(message));
							}

							if (message.ResultOutcome == null) message.ResultOutcome = RelayOutcome.Queued;
							node.HandleInMessage(serializedMessageInterZone);
						}
						else if (typesettingSyncInMessages)
						{
							messageHandled = node.HandleInMessageSync(message, typesettingSyncInMessages, typesettingThrowOnSyncFailure);
						}
						else
						{
							if (message.ResultOutcome == null) message.ResultOutcome = RelayOutcome.Queued;
							node.HandleInMessage(serializedMessage);
						}

						if (!messageHandled)
						{
							throw new SyncRelayOperationException(string.Format("Node {0} failed to process message {1}\r\n", node, message));
						}
					}
				}
			}
		}
Пример #8
0
		private IAsyncResult BeginDoHandleMessage(RelayMessage message, bool useSyncForInMessages, bool skipErrorQueueForSync, AsyncCallback callback, object asyncState)
		{
			var asyncTransport = _transport as IAsyncRelayTransport;

			if (asyncTransport == null) 
			{
				return NodeSynchronousAsyncResult.CreateAndComplete(DoHandleMessage(message, useSyncForInMessages, skipErrorQueueForSync), callback, asyncState);
			}

			bool alwaysHandled = !useSyncForInMessages || !skipErrorQueueForSync;

			if (!Activated || message == null)
			{
				if (message != null) message.ResultOutcome = RelayOutcome.NotSent;
				return NodeSynchronousAsyncResult.CreateAndComplete(alwaysHandled, callback, asyncState);
			}

			if (DangerZone)
			{
				//this is only called for synchronous messages, which aren't error queued
				message.SetError(RelayErrorType.NodeInDanagerZone);
				return NodeSynchronousAsyncResult.CreateAndComplete(alwaysHandled, callback, asyncState);
			}

			var watch = GatherStats ? Stopwatch.StartNew() : null;
			try
			{
				NodeManager.Instance.Counters.CountMessage(message);
				var result = new AsynchronousResult(message, useSyncForInMessages, skipErrorQueueForSync);
				message.ResultOutcome = RelayOutcome.Queued; // close enough
				result.InnerResult = asyncTransport.BeginSendMessage(message, useSyncForInMessages, asyncResult =>
				{
					if (watch != null)
					{
						watch.Stop();
						CaculateStatisics(message, watch.ElapsedMilliseconds);
					}
					if (callback != null)
					{
						result.InnerResult = asyncResult;
						callback(result);
					}
				}, asyncState);
				return result;
			}
			catch (Exception ex)
			{
				//this is only called for get messages, which aren't error queued
				InstrumentException(ex);
				message.SetError(ex);
				NodeGroup.LogNodeException(message, this, ex);

				return NodeSynchronousAsyncResult.CreateAndComplete(alwaysHandled, callback, asyncState);
			}
			finally
			{
				if (watch != null)
				{
					watch.Stop();
					CaculateStatisics(message, watch.ElapsedMilliseconds);
				}
			}
		}
Пример #9
0
		/// <summary>
		/// Processes a single message
		/// </summary>
		/// <param name="message">Message to be processed</param>
		/// <param name="useSyncForInMessages">Default: false
		/// The type (from TypeSettings.config) can require synchronous handling for messages
		/// </param>
		/// <param name="skipErrorQueueForSync">Default: false
		/// The type (from TypeSettings.config) can require that should the message processing fail,
		/// the message will NOT be sent to the Error Queue for retry.  Instead, the function returns
		/// false.
		/// Has no effect if useSyncForInMessages is false.
		/// </param>
		/// <returns>
		/// useSyncForInMessages = false	always returns True (message processed Async)
		/// useSyncForInMessages = true, skipErrorQueueForSync = false	always returns True (errors placed in queue for retry)
		/// useSyncForInMessages = true, skipErrorQueueForSync = true	returns true if the message processing succeeded
		/// </returns>
		private bool DoHandleMessage(RelayMessage message, bool useSyncForInMessages, bool skipErrorQueueForSync)
		{
			try
			{
				if (!Activated || message == null)
				{
					if (skipErrorQueueForSync && useSyncForInMessages)
					{
						return false;
					}
					return true;
				}

				if (DangerZone)
				{
					//this is only called for synchronous messages, which aren't error queued
					message.SetError(RelayErrorType.NodeInDanagerZone);
					if (skipErrorQueueForSync && useSyncForInMessages)
					{
						return false;
					}
					return true;
				}

				bool messageHandled = true;

				try
				{
					if (GatherStats)
					{
						Stopwatch watch = Stopwatch.StartNew();
						if (useSyncForInMessages)
						{
							// using the system this way allows us to continue on if the 
							// Transport does not expose IRelayTransportExtended.
							// The old handling (Transport.SendMessage) will send "put" 
							// messages one-way, preventing certain errors from being
							// reported, but this does not break any existing code
							IRelayTransportExtended TransportEx = _transport as IRelayTransportExtended;
							if (null != TransportEx)
							{
								TransportEx.SendSyncMessage(message);
							}
							else
							{
								_transport.SendMessage(message);
							}
						}
						else
						{
							_transport.SendMessage(message);
						}
						watch.Stop();
						CaculateStatisics(message, watch.ElapsedMilliseconds);
					}
					else
					{
						if (useSyncForInMessages)
						{
							// using the system this way allows us to continue on if the 
							// Transport does not expose IRelayTransportExtended.
							// The old handling (Transport.SendMessage) will send "put" 
							// messages one-way, preventing certain errors from being
							// reported, but this does not break any existing code
							IRelayTransportExtended TransportEx = _transport as IRelayTransportExtended;
							if (null != TransportEx)
							{
								TransportEx.SendSyncMessage(message);
							}
							else
							{
								_transport.SendMessage(message);
							}
						}
						else
						{
							_transport.SendMessage(message);
						}
					}
					
					if (message.ErrorOccurred)
					{
						messageHandled = false;
					}
					
					NodeManager.Instance.Counters.CountMessage(message);
				}
				catch (Exception ex)
				{
					if (skipErrorQueueForSync && useSyncForInMessages)
					{
						messageHandled = false;
					}

					//this is only called for get messages, which aren't error queued				
					InstrumentException(ex);
					message.SetError(ex);
					NodeGroup.LogNodeException(message, this, ex);
				}
				return messageHandled;
			}
			finally
			{
				if (message != null && message.ResultOutcome == null)
				{
					message.ResultOutcome = RelayOutcome.NotSent;
				}
			}
		}