public void SetNextState(ServiceFabricAutopilotAgentState nextState, bool toIgnoreStateTransitionWhenStopping = true)
        {
            lock (this.StatusLock)
            {
                if (toIgnoreStateTransitionWhenStopping && this.State < ServiceFabricAutopilotAgentState.Started)
                {
                    TextLogger.LogVerbose("Application is stopping. Ignore state transition request to {0}.", nextState);

                    return;
                }

                TextLogger.LogInfo("State transition: {0} -> {1}", this.State, nextState);

                this.State = nextState;
            }
        }
        private void RunStateMachine()
        {
            bool toRunStateMachineCore = false;

            lock (this.agentStatus.StatusLock)
            {
                if (this.agentStatus.State < ServiceFabricAutopilotAgentState.Started)
                {
                    return;
                }

                TextLogger.LogVerbose("RunStateMachine : {0}.", this.agentStatus);

                if (this.agentStatus.LastFailedDeploymentAction != DateTime.MinValue && (DateTime.UtcNow - this.agentStatus.LastFailedDeploymentAction).TotalSeconds < ConfigurationManager.DeploymentRetryIntervalSeconds)
                {
                    return;
                }

                // Note that when a deployer operation (node configuration creation or update) fails, it would be retried based on the same cluster manifest (bootstrap or current).
                // I.e a retry would happen even when a previous operation failed with the same cluster manifest.
                if ((this.agentStatus.State > ServiceFabricAutopilotAgentState.Started && agentStatus.State < ServiceFabricAutopilotAgentState.DiscoveringTopology) ||
                    (this.agentStatus.State == ServiceFabricAutopilotAgentState.DiscoveringTopology && ConfigurationManager.BootstrapClusterManifestLocation != BootstrapClusterManifestLocationType.NotReady) ||
                    (this.agentStatus.State > ServiceFabricAutopilotAgentState.DiscoveringTopology && agentStatus.State < ServiceFabricAutopilotAgentState.NodeStarted) ||
                    (this.agentStatus.State == ServiceFabricAutopilotAgentState.NodeStarted && !this.agentStatus.ExpectedTopologyRunning))
                {
                    TextLogger.LogInfo(
                        "RunStateMachine: current agent state necessitates RunStateMachineCore. Agent status = {0}, ExpectedTopologyRunning = {1}, LastFailedDeploymentAction = {2}, BootstrapClusterManifestLocation = {3}.",
                        this.agentStatus.State,
                        this.agentStatus.ExpectedTopologyRunning,
                        this.agentStatus.LastFailedDeploymentAction,
                        ConfigurationManager.BootstrapClusterManifestLocation);

                    toRunStateMachineCore = true;
                }
            }

            if (toRunStateMachineCore)
            {
                bool coreStateMachineRunResult;
                ServiceFabricAutopilotAgentState currentState;

                do
                {
                    currentState = this.agentStatus.GetCurrentState();

                    if (currentState < ServiceFabricAutopilotAgentState.Started)
                    {
                        return;
                    }

                    coreStateMachineRunResult = this.RunStateMachineCore(currentState);

                    TextLogger.LogInfo("RunStateMachine: RunStateMachineCore completed with result {0}. State prior to the run : {1}.", coreStateMachineRunResult, currentState);

                    if (!coreStateMachineRunResult)
                    {
                        lock (agentStatus.StatusLock)
                        {
                            this.agentStatus.LastFailedDeploymentAction = DateTime.UtcNow;
                        }
                    }
                    else
                    {
                        lock (agentStatus.StatusLock)
                        {
                            this.agentStatus.LastFailedDeploymentAction = DateTime.MinValue;
                        }
                    }

                    currentState = this.agentStatus.GetCurrentState();
                }while (currentState > ServiceFabricAutopilotAgentState.Started && currentState < ServiceFabricAutopilotAgentState.NodeStarted && coreStateMachineRunResult);
            }
        }