// TODO check mining pairs /// <summary> /// Sets <see cref="DesiredRunningState"/> to Start if not already so. Then creates a miningProcess and awaits for stop token. Also handles restarts of miningProcess in case of errors. /// </summary> public void StartMining() { lock (_lock) { if (_desiredState == DesiredRunningState.Start) { Logger.Error(_logGroup, $"Trying to start an already started miner"); return; } Logger.Info(_logGroup, $"Starting miner watchdog task"); _desiredState = DesiredRunningState.Start; } //const int ERROR_FILE_NOT_FOUND = 0x2; //const int ERROR_ACCESS_DENIED = 0x5; Task.Run(() => { using (var stopMiner = new CancellationTokenSource()) { lock (_lock) { _stopMiners.Add(stopMiner); } var run = IsStart() && stopMiner.IsCancellationRequested == false; while (run) { var binPathBinCwdPair = GetBinAndCwdPaths(); var binPath = binPathBinCwdPair.Item1; var binCwd = binPathBinCwdPair.Item2; var commandLine = MiningCreateCommandLine(); var environmentVariables = GetEnvironmentVariables(); using (var miningProcess = MinerToolkit.CreateMiningProcess(binPath, binCwd, commandLine, environmentVariables)) { lock (_lock) { _miningProcess = miningProcess; } var quitMiningProcess = stopMiner.Token.Register(() => { try { var pid = miningProcess?.Id ?? -1; miningProcess?.CloseMainWindow(); // 5 seconds wait for shutdown var hasExited = !miningProcess?.WaitForExit(5 * 1000) ?? false; var stillRunning = pid > -1 ? Process.GetProcessById(pid) != null : false; if (!hasExited || stillRunning) { miningProcess?.Kill(); // TODO look for another gracefull shutdown } } catch (Exception e) { Logger.Info(_logGroup, $"Error occured while stopping the process: {e.Message}"); } }); try { // mandatory 500ms delay Task.Delay(500).Wait(); // BEFORE ThrowIfIsStop(stopMiner.IsCancellationRequested); if (this is IBeforeStartMining bsm) { bsm.BeforeStartMining(); } ThrowIfIsStop(stopMiner.IsCancellationRequested); // Logging Logger.Info(_logGroup, $"Starting miner binPath='{binPath}'"); Logger.Info(_logGroup, $"Starting miner binCwd='{binCwd}'"); Logger.Info(_logGroup, $"Starting miner commandLine='{commandLine}'"); // TODO this will not print content var environmentVariablesLog = environmentVariables == null ? "<null>" : string.Join(";", environmentVariables.Select(x => x.Key + "=" + x.Value)); Logger.Info(_logGroup, $"Starting miner environmentVariables='{environmentVariablesLog}'"); // TODO log or debug??? ThrowIfIsStop(stopMiner.IsCancellationRequested); //_stopMiner = new CancellationTokenSource(); { if (!miningProcess.Start()) { Logger.Info(_logGroup, $"Error occured while starting a new process: {miningProcess.ToString()}"); throw new InvalidOperationException("Could not start process: " + miningProcess); } ThrowIfIsStop(stopMiner.IsCancellationRequested); if (this is IAfterStartMining asm) { asm.AfterStartMining(); } ThrowIfIsStop(stopMiner.IsCancellationRequested); // block loop until process is running miningProcess.WaitForExit(); } } //catch (Win32Exception ex2) //{ // ////if (ex2.NativeErrorCode == ERROR_FILE_NOT_FOUND) throw ex2; // //Logger.Info(_logGroup, $"Win32Exception Error occured in StartMining : {ex2.ToString()}"); // //Task.Delay(MinerToolkit.MinerRestartDelayMS, _stopMiner.Token).Wait(); //} catch (StopMinerWatchdogException) { Logger.Info(_logGroup, $"Watchdog stopped in StartMining"); } catch (Exception e) { Logger.Error(_logGroup, $"Error occured in StartMining : {e.Message}"); } finally { quitMiningProcess.Dispose(); // delay restart run = IsStart() && stopMiner.IsCancellationRequested == false; if (run) { Logger.Info(_logGroup, $"Restart Mining in {MinerToolkit.MinerRestartDelayMS}ms"); Task.Delay(MinerToolkit.MinerRestartDelayMS).Wait(); } } } } Logger.Info(_logGroup, $"Exited miner watchdog"); lock (_lock) { _stopMiners.Remove(stopMiner); } } }); }
public Task <object> StartMiningTask(CancellationToken stop) { //const int ERROR_FILE_NOT_FOUND = 0x2; //const int ERROR_ACCESS_DENIED = 0x5; // tsc for started process var startProcessTaskCompletionSource = new TaskCompletionSource <object>(); var binPathBinCwdPair = GetBinAndCwdPaths(); var binPath = binPathBinCwdPair.Item1; var binCwd = binPathBinCwdPair.Item2; var commandLine = MiningCreateCommandLine(); var environmentVariables = GetEnvironmentVariables(); var stopActionExec = false; _miningProcessTask = Task.Run(() => { using (_stopMinerTaskSource = new CancellationTokenSource()) using (var stopMinerTask = CancellationTokenSource.CreateLinkedTokenSource(stop, _stopMinerTaskSource.Token)) using (var miningProcess = MinerToolkit.CreateMiningProcess(binPath, binCwd, commandLine, environmentVariables)) using (var quitMiningProcess = stopMinerTask.Token.Register(() => ExitMiningProcess(miningProcess))) { lock (_lock) { _miningProcess = miningProcess; } try { // BEFORE ThrowIfIsStop(stopMinerTask.IsCancellationRequested); if (this is IBeforeStartMining bsm) { bsm.BeforeStartMining(); } ThrowIfIsStop(stopMinerTask.IsCancellationRequested); // Logging Logger.Info(_logGroup, $"Starting miner binPath='{binPath}'"); Logger.Info(_logGroup, $"Starting miner binCwd='{binCwd}'"); Logger.Info(_logGroup, $"Starting miner commandLine='{commandLine}'"); var environmentVariablesLog = environmentVariables == null ? "<null>" : string.Join(";", environmentVariables.Select(x => x.Key + "=" + x.Value)); Logger.Info(_logGroup, $"Starting miner environmentVariables='{environmentVariablesLog}'"); ThrowIfIsStop(stopMinerTask.IsCancellationRequested); // exec START custom scripts if any, must be here if blocking ExecMinerCustomActionSettings(true); if (!miningProcess.Start()) { Logger.Info(_logGroup, $"Error occured while starting a new process: {miningProcess.ToString()}"); startProcessTaskCompletionSource.SetResult(new InvalidOperationException("Could not start process: " + miningProcess)); return; } startProcessTaskCompletionSource.SetResult(true); ThrowIfIsStop(stopMinerTask.IsCancellationRequested); if (this is IAfterStartMining asm) { asm.AfterStartMining(); } ThrowIfIsStop(stopMinerTask.IsCancellationRequested); // block while process is running miningProcess.WaitForExit(); // exec STOP custom scripts if any, must be here if blocking stopActionExec = true; ExecMinerCustomActionSettings(false); } //catch (Win32Exception ex2) //{ // ////if (ex2.NativeErrorCode == ERROR_FILE_NOT_FOUND) throw ex2; // //Logger.Info(_logGroup, $"Win32Exception Error occured in StartMining : {ex2.ToString()}"); // //Task.Delay(MinerToolkit.MinerRestartDelayMS, _stopMiner.Token).Wait(); //} catch (StopMinerWatchdogException) { Logger.Info(_logGroup, $"Watchdog stopped in StartMining"); startProcessTaskCompletionSource.SetResult(false); } catch (Exception e) { Logger.Error(_logGroup, $"Error occured in StartMining : {e.Message}"); startProcessTaskCompletionSource.SetResult(e); } finally { if (!stopActionExec) { // exec STOP custom scripts if any, last resort it will not block but it is a fallback option ExecMinerCustomActionSettings(false); } } } }); return(startProcessTaskCompletionSource.Task); }