예제 #1
0
        /// <summary>
        ///     Initializes a new instance of <see cref="ProcessSupervisor"/>
        /// </summary>
        /// <param name="workingDirectory">
        ///     The working directory to start the process in.
        /// </param>
        /// <param name="processPath">
        ///     The path to the process.
        /// </param>
        /// <param name="processRunType">
        ///     The process run type.
        /// </param>
        /// <param name="arguments">
        ///     Arguments to be passed to the process.
        /// </param>
        /// <param name="environmentVariables">
        ///     Environment variables that are set before the process starts.
        /// </param>
        public ProcessSupervisor(
            ProcessRunType processRunType,
            string workingDirectory,
            string processPath,
            string arguments = null,
            StringDictionary environmentVariables = null,
            bool captureStdErr = false)
        {
            _workingDirectory     = workingDirectory;
            _processPath          = processPath;
            _arguments            = arguments ?? string.Empty;
            _environmentVariables = environmentVariables;
            _captureStdErr        = captureStdErr;

            _logger = LogProvider.GetLogger($"ProcessSupervisor-{processPath}");

            _processStateMachine
            .Configure(State.NotStarted)
            .Permit(Trigger.Start, State.Running);

            _startErrorTrigger = _processStateMachine.SetTriggerParameters <Exception>(Trigger.StartError);
            _stopTrigger       = _processStateMachine.SetTriggerParameters <TimeSpan?>(Trigger.Stop);

            _processStateMachine
            .Configure(State.Running)
            .OnEntryFrom(Trigger.Start, OnStart)
            .PermitIf(
                Trigger.ProcessExit,
                State.ExitedSuccessfully,
                () => processRunType == ProcessRunType.SelfTerminating && _process.ExitCode == 0,
                "SelfTerminating && ExitCode==0")
            .PermitIf(
                Trigger.ProcessExit,
                State.ExitedWithError,
                () => processRunType == ProcessRunType.SelfTerminating && _process.ExitCode != 0,
                "SelfTerminating && ExitCode!=0")
            .PermitIf(
                Trigger.ProcessExit,
                State.ExitedUnexpectedly,
                () => processRunType == ProcessRunType.NonTerminating,
                "NonTerminating")
            .Permit(Trigger.Stop, State.Stopping)
            .Permit(Trigger.StartError, State.StartFailed);

            _processStateMachine
            .Configure(State.StartFailed)
            .OnEntryFrom(_startErrorTrigger, OnStartError);

            _processStateMachine
            .Configure(State.Stopping)
            .Permit(Trigger.ProcessExit, State.ExitedSuccessfully)
            .OnEntryFromAsync(_stopTrigger, OnStop);

            _processStateMachine
            .Configure(State.StartFailed)
            .Permit(Trigger.Start, State.Running);

            _processStateMachine
            .Configure(State.ExitedSuccessfully)
            .Permit(Trigger.Start, State.Running);

            _processStateMachine
            .Configure(State.ExitedUnexpectedly)
            .Permit(Trigger.Start, State.Running);

            _processStateMachine.OnTransitioned(transition =>
            {
                _logger.Info($"State transition from {transition.Source} to {transition.Destination}");
                StateChanged?.Invoke(transition.Destination);
            });
        }
예제 #2
0
        /// <summary>
        ///     Initializes a new instance of <see cref="ProcessSupervisor"/>
        /// </summary>
        /// <param name="workingDirectory">
        ///     The working directory to start the process in.
        /// </param>
        /// <param name="processPath">
        ///     The path to the process.
        /// </param>
        /// <param name="processRunType">
        ///     The process run type.
        /// </param>
        /// <param name="loggerFactory">
        ///     A logger factory.
        /// </param>
        /// <param name="arguments">
        ///     Arguments to be passed to the process.
        /// </param>
        /// <param name="environmentVariables">
        ///     Environment variables that are set before the process starts.
        /// </param>
        /// <param name="captureStdErr">
        ///     A flag to indicated whether to capture standard error output.
        /// </param>
        public ProcessSupervisor(
            ILoggerFactory loggerFactory,
            ProcessRunType processRunType,
            string workingDirectory,
            string processPath,
            string arguments = null,
            StringDictionary environmentVariables = null,
            bool captureStdErr = false)
        {
            _loggerFactory        = loggerFactory;
            _workingDirectory     = workingDirectory;
            _processPath          = processPath;
            _arguments            = arguments ?? string.Empty;
            _environmentVariables = environmentVariables;
            _captureStdErr        = captureStdErr;

            _logger = loggerFactory.CreateLogger($"{nameof(LittleForker)}.{nameof(ProcessSupervisor)}-{processPath}");

            _processStateMachine
            .Configure(State.NotStarted)
            .Permit(Trigger.Start, State.Running);

            _startErrorTrigger = _processStateMachine.SetTriggerParameters <Exception>(Trigger.StartError);
            _stopTrigger       = _processStateMachine.SetTriggerParameters <TimeSpan?>(Trigger.Stop);

            _processStateMachine
            .Configure(State.Running)
            .OnEntryFrom(Trigger.Start, OnStart)
            .PermitIf(
                Trigger.ProcessExit,
                State.ExitedSuccessfully,
                () => processRunType == ProcessRunType.SelfTerminating &&
                _process.HasExited &&
                _process.ExitCode == 0,
                "SelfTerminating && ExitCode==0")
            .PermitIf(
                Trigger.ProcessExit,
                State.ExitedWithError,
                () => processRunType == ProcessRunType.SelfTerminating &&
                _process.HasExited &&
                _process.ExitCode != 0,
                "SelfTerminating && ExitCode!=0")
            .PermitIf(
                Trigger.ProcessExit,
                State.ExitedUnexpectedly,
                () => processRunType == ProcessRunType.NonTerminating &&
                _process.HasExited,
                "NonTerminating and died.")
            .Permit(Trigger.Stop, State.Stopping)
            .Permit(Trigger.StartError, State.StartFailed);

            _processStateMachine
            .Configure(State.StartFailed)
            .OnEntryFrom(_startErrorTrigger, OnStartError);

            _processStateMachine
            .Configure(State.Stopping)
            .OnEntryFromAsync(_stopTrigger, OnStop)
            .PermitIf(Trigger.ProcessExit, State.ExitedSuccessfully,
                      () => processRunType == ProcessRunType.NonTerminating &&
                      !_killed &&
                      _process.HasExited &&
                      _process.ExitCode == 0,
                      "NonTerminating and shut down cleanly")
            .PermitIf(Trigger.ProcessExit, State.ExitedWithError,
                      () => processRunType == ProcessRunType.NonTerminating &&
                      !_killed &&
                      _process.HasExited &&
                      _process.ExitCode != 0,
                      "NonTerminating and shut down with non-zero exit code")
            .PermitIf(Trigger.ProcessExit, State.ExitedKilled,
                      () => processRunType == ProcessRunType.NonTerminating &&
                      _killed &&
                      _process.HasExited &&
                      _process.ExitCode != 0,
                      "NonTerminating and killed.");

            _processStateMachine
            .Configure(State.StartFailed)
            .Permit(Trigger.Start, State.Running);

            _processStateMachine
            .Configure(State.ExitedSuccessfully)
            .Permit(Trigger.Start, State.Running);

            _processStateMachine
            .Configure(State.ExitedUnexpectedly)
            .Permit(Trigger.Start, State.Running);

            _processStateMachine
            .Configure(State.ExitedKilled)
            .Permit(Trigger.Start, State.Running);

            _processStateMachine.OnTransitioned(transition =>
            {
                _logger.LogInformation($"State transition from {transition.Source} to {transition.Destination}");
                StateChanged?.Invoke(transition.Destination);
            });
        }