/// <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)); }
internal void Add(RelayMessage message, SimpleLinkedList <Node> nodes) { TypeSetting typeSetting = NodeManager.Instance.Config.TypeSettings.TypeSettingCollection[message.TypeId]; Node node; while (nodes.Pop(out node)) { bool typesettingThrowOnSyncFailure = false; bool typesettingSyncInMessages = false; if (null != typeSetting && !node.NodeCluster.MeInThisCluster) { typesettingSyncInMessages = typeSetting.SyncInMessages; typesettingThrowOnSyncFailure = typeSetting.ThrowOnSyncFailure; } // Contains no longer works now that the NodeWithMessages structure has // been added, loop through and check the settings bool bAdded = false; foreach (NodeWithMessages nwm in this) { NodeWithInfo nwi = GetKeyForItem(nwm); if ((nwi.Node == node) && (nwi.SyncInMessages == typesettingSyncInMessages) && (nwi.SkipErrorQueueForSync == typesettingThrowOnSyncFailure)) { bAdded = true; this[nwi].Messages.Add(message); break; } } if (!bAdded) { NodeWithInfo newNWI = new NodeWithInfo(node, typesettingSyncInMessages, typesettingThrowOnSyncFailure); NodeWithMessages newNode = new NodeWithMessages(newNWI); Add(newNode); this[newNWI].Messages.Add(message); } } }
/// <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)); } } } } }
/// <summary> /// Splits messages into various lists of in and out message destined for different nodes. /// </summary> /// <param name="messages"></param> /// <returns></returns> internal NodeWithMessagesCollection DistributeMessages(IList <RelayMessage> messages) { NodeWithMessagesCollection distribution = new NodeWithMessagesCollection(); RelayMessage message; Node node; for (int i = 0; i < messages.Count; i++) { if (messages[i] != null) { message = messages[i]; RelayMessage interZoneMessage = null; SimpleLinkedList <Node> nodesForMessage = GetNodesForMessage(message); SimpleLinkedList <Node> nodesForInterZoneMessage = null; if (nodesForMessage.Count > 0) { message.AddressHistory.Add(MyIpAddress); } message.RelayTTL--; #region Identify InterZone Messages if (message.IsTwoWayMessage == false) { message.ResultOutcome = RelayOutcome.Queued; //will be queued, if sync will not get overwritten // Identify nodes in foreign zones int nodeCount = nodesForMessage.Count; for (int nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++) { nodesForMessage.Pop(out node); if (_myNodeDefinition != null && _myNodeDefinition.Zone != node.NodeDefinition.Zone) { // Message needs to cross Zone bounderies if (interZoneMessage == null) { interZoneMessage = RelayMessage.CreateInterZoneMessageFrom(message); nodesForInterZoneMessage = new SimpleLinkedList <Node>(); } nodesForInterZoneMessage.Push(node); } else { nodesForMessage.Push(node); } } } #endregion if (nodesForMessage.Count > 0) { DebugWriter.WriteDebugInfo(message, nodesForMessage); distribution.Add(message, nodesForMessage); } if (nodesForInterZoneMessage != null && nodesForInterZoneMessage.Count > 0) { DebugWriter.WriteDebugInfo(interZoneMessage, nodesForInterZoneMessage); distribution.Add(interZoneMessage, nodesForInterZoneMessage); } } } return(distribution); }