private void GetSuccessorTable(CorrelationId operationId, NodeInfo applicantInfo)
            {
                var assembledReply = new GetSuccessorTableReply(_node.Identity, applicantInfo, operationId)
                {
                    SuccessorTable = new RoutingTableEntry[_node.Config.SuccessorCount],
                };

                var totalTimeout = _node.Config.SuccessorCount * _node.Config.AwaitSettings.NetworkQueryTimeout;

                var multiReplyHandler = _node.CreateAwaitAllResponsesHandler();

                multiReplyHandler
                .PerformAction(() =>
                {
                    var thisNode       = _node.Identity;
                    var initialMessage = new GetSuccessorTable(thisNode, thisNode, operationId)
                    {
                        Applicant      = applicantInfo,
                        SuccessorTable = new RoutingTableEntry[_node.Config.SuccessorCount],
                        HopCount       = 0,
                    };

                    _node.Log($"Sending {initialMessage.TypeName()} To {initialMessage.To} Id:{initialMessage.CorrelationId}");
                    _commMgr.SendInternal(initialMessage);
                })
                .AndAwait(operationId, (GetSuccessorTableReply successorReply) =>
                {
                    assembledReply.SuccessorTable = successorReply.SuccessorTable;
                })
                .ContinueWith(() =>
                {
                    // Merge the result back with the parent query
                    _commMgr.SendInternal(assembledReply);
                })
                .Run(operationId, totalTimeout);
            }
            public void Handle(GetSuccessorTable message)
            {
                _node.LogMessage(message);
                _commMgr.SendAck(message, message.CorrelationId);

                var applicant = message.Applicant;

                if (_node.IsInDomain(applicant.RoutingHash))
                {
                    _node.Log($"{applicant} IsInDomain");
                    // the predecessors successor table will become the applicant's if the applicant node
                    // becomes the new predecessor. The head of the predecessors table is this node.

                    var nextSuccessor    = _node.Identity;
                    var returnAddress    = message.From;
                    var tableLength      = _node.SuccessorTable.Length;
                    var predecessorTable = new RoutingTableEntry[_node.SuccessorTable.Length];
                    if (tableLength > 1)
                    {
                        var thisTable = _node.SuccessorTable;
                        for (int i = 0; i < predecessorTable.Length - 1; i++)
                        {
                            predecessorTable[i + 1] = thisTable[i];
                        }
                    }

                    predecessorTable[0] = new RoutingTableEntry(_node.Identity.RoutingHash, _node.Identity);

                    var reply = new GetSuccessorTableReply(_node.Identity, returnAddress, message.CorrelationId)
                    {
                        SuccessorTable = predecessorTable,
                    };
                    _node.Log($"Sending {reply.TypeName()}");
                    _commMgr.Send(reply);


                    //message.SuccessorTable[message.HopCount] = new RoutingTableEntry(nextSuccessor.RoutingHash, nextSuccessor);

                    //var hopMax = _node.Config.SuccessorCount - 1;
                    //if (message.HopCount < hopMax)
                    //{
                    //    nextSuccessor = _node.Successor;
                    //    _node.Log($"Successor({message.HopCount}) found. Forwarding to {nextSuccessor}");

                    //    var forwardMsg = message;
                    //    forwardMsg.To = nextSuccessor;
                    //    forwardMsg.HopCount++;
                    //    forwardMsg.Applicant = nextSuccessor; // we need to now follow a chain of successors

                    //    _commMgr.Send(forwardMsg);
                    //}
                    //else
                    //{
                    //    // we've collected all the successors. Now send them home
                    //    var returnAddress = message.From;
                    //    var reply = new GetSuccessorTableReply(_node.Identity, returnAddress, message.CorrelationId)
                    //    {
                    //        SuccessorTable = message.SuccessorTable,
                    //    };
                    //    _node.Log($"Sending {reply.TypeName()} Successor({message.HopCount}) found.");
                    //    _commMgr.Send(reply);
                    //}
                }
                else // Ask the network
                {
                    var closestNode = _node.SuccessorTable.FindClosestPrecedingFinger(applicant.RoutingHash);
                    message.To = closestNode;
                    _node.Log($"Routing {message.TypeName()} {message.To}");
                    _commMgr.Send(message);
                }
            }