public void HappyPath()
        {
            ISwimProtocolProvider protocolProvider = new SwimProtocolProvider(null, _output);

            var loggerFactory = new LoggerFactory();

            loggerFactory.AddProvider(new XunitLoggerProvider(_output));

            var swimProtocol = new FailureDetection(protocolProvider, _configuration, loggerFactory.CreateLogger <FailureDetection>());

            swimProtocol.OnTransitioned((action) =>
            {
                _output.WriteLine($"{action.Source} => {action.Trigger} => {action.Destination}");
            });

            swimProtocol.Fire(SwimFailureDetectionTrigger.Ping);
            Assert.Equal(SwimFailureDetectionState.Pinged, swimProtocol.State);

            swimProtocol.Fire(SwimFailureDetectionTrigger.PingExpireLive);
            Assert.Equal(SwimFailureDetectionState.Alive, swimProtocol.State);

            swimProtocol.Fire(SwimFailureDetectionTrigger.ProtocolExpireLive);
            Assert.Equal(SwimFailureDetectionState.Expired, swimProtocol.State);

            swimProtocol.Fire(SwimFailureDetectionTrigger.Reset);
            Assert.Equal(SwimFailureDetectionState.Idle, swimProtocol.State);
        }
Example #2
0
    public async Task <Response> SendAsync(uint?nextHop, Request request, int timeout, int attempts)
    {
        comms.Node.SleepCount++;


        int retryDelay = 1000;
        TaskCompletionSource <Response> tcs = new TaskCompletionSource <Response>();
        bool AckReceived = false;

        void GetResponse(object sender, ResponseEventArgs e)
        {
            if (e.Response.MessageIdentifer == request.MessageIdentifer)
            {
                if (request.SourceID != comms.Node.Id)
                {
                    if (request.AckExpected && e.Response.ResponseCode == Response.ResponseCodes.ACK)
                    {
                        OnResponseReceived -= GetResponse;
                        tcs.SetResult(e.Response);
                        return;
                    }
                }

                if (request.ResponseExpected)
                {
                    if (e.Response.ResponseCode == Response.ResponseCodes.ACK)
                    {
                        AckReceived = true;
                    }
                    else
                    {
                        OnResponseReceived -= GetResponse;
                        tcs.SetResult(e.Response);
                        return;
                    }
                }
                else if (request.AckExpected)
                {
                    OnResponseReceived -= GetResponse;
                    tcs.SetResult(e.Response);
                    return;
                }
            }
        }

        new Thread(() =>
        {
            OnResponseReceived += GetResponse;


            // Attempt to send multiple times, break loop if response
            for (int i = 0; i < attempts; i++)
            {
                if (AckReceived == false)
                {
                    Send(nextHop, request);

                    Thread.Sleep(timeout / Constants.TimeScale);

                    // Delay and retry with increasing delay
                    if (tcs.Task.IsCompleted == false)
                    {
                        Thread.Sleep(retryDelay / Constants.TimeScale);

                        retryDelay *= 2;
                    }
                    else
                    {
                        break;
                    }
                }
            }

            if (tcs.Task.IsCompleted == false)
            {
                Response response = new Response()
                {
                    SourceID         = request.DestinationID,
                    DestinationID    = request.SourceID,
                    MessageIdentifer = request.MessageIdentifer,
                    ResponseCode     = Response.ResponseCodes.TIMEOUT
                };
                tcs.SetResult(response);
            }
        }).Start();

        await tcs.Task;

        // Trigger failure handling if no response after several attempts
        if (request.GetType() != typeof(DetectFailureRequest) && request.Command != Request.Commands.PING && tcs.Task.Result.ResponseCode == Response.ResponseCodes.TIMEOUT)
        {
            FailureDetection.FailureDetected(comms.Node, nextHop);
        }
        // Trigger recovery if no response after several attempts and already failure handling and attempted node is not the one to be checked via failure handling
        else if (request.GetType() == typeof(DetectFailureRequest) && tcs.Task.Result.ResponseCode == Response.ResponseCodes.TIMEOUT && (request as DetectFailureRequest).NodeToCheck != nextHop)
        {
            FailureDetection.Recovery(comms.Node, nextHop);
        }


        comms.Node.SleepCount--;


        return(tcs.Task.Result);
    }
Example #3
0
    private async void ExecuteRequest(Request request, bool isDependency)
    {
        switch (request.Command)
        {
        case Request.Commands.GENERATE:
            PlanGenerator.GeneratePlan(this, request as PlanRequest);
            break;

        case Request.Commands.EXECUTE:
            PlanExecuter.ExecutePlan(this, request as PlanRequest);
            break;

        case Request.Commands.HEARTBEAT:
            Heartbeat.RespondToHeartbeat(this, request);
            break;

        case Request.Commands.PING:
            Ping.RespondToPing(this, request);
            break;

        case Request.Commands.DETECTFAILURE:
            FailureDetection.DetectFailure(this, request as DetectFailureRequest);
            break;

        case Request.Commands.DISCOVER:

            await Discovery.DiscoverAsync(this, request as DiscoveryRequest);

            break;

        case Request.Commands.POSITION:
            PositionResponse response = new PositionResponse(Id, request.SourceID, Response.ResponseCodes.OK, request.MessageIdentifer, Position);
            CommsModule.Send(request.SourceID, response);
            break;

        case Request.Commands.ADDITION:

            List <uint?>    neighbours = CommsModule.Discover();
            AdditionRequest addition   = (request as AdditionRequest).DeepCopy();

            List <ConstellationPlanField> fields = new List <ConstellationPlanField> {
                new ConstellationPlanField("DeltaV", 0, (x, y) => x.CompareTo(y))
            };
            addition.plan.Entries.Add(new ConstellationPlanEntry(Id, Position, fields, (x, y) => 1));
            ActivePlan = addition.plan;
            Router.UpdateNetworkMap(addition.plan);

            NodeAdditionResponse additionResponse = new NodeAdditionResponse(Id, request.SourceID, Response.ResponseCodes.OK, request.MessageIdentifer, Position, neighbours);
            CommsModule.Send(request.SourceID, additionResponse);
            break;

        case Request.Commands.UPDATENETWORKMAP:
            NetworkUpdateRequest updateRequest = request as NetworkUpdateRequest;

            //Remove any dead nodes from the networkmap
            Router.NetworkMap.Entries.RemoveAll(entry => updateRequest.DeadNodes.Contains(entry.ID));

            //Remove any dead nodes from neighbour lists
            foreach (NetworkMapEntry entry in Router.NetworkMap.Entries)
            {
                foreach (uint?deadNode in updateRequest.DeadNodes)
                {
                    entry.Neighbours.Remove(deadNode);
                }
            }
            break;

        default:
            throw new NotImplementedException(request.Command.ToString() + " was not implemented.");
        }
    }