/// <summary> /// Stops bitcoin daemon process when PID file exists. /// </summary> /// <remarks>If there is not PID file, no process is stopped.</remarks> /// <param name="onlyOwned">Only stop if this node owns the process.</param> public async Task StopAsync(bool onlyOwned) { Logger.LogDebug($"> {nameof(onlyOwned)}={onlyOwned}"); if (Process is null) { Logger.LogDebug("< Process is null."); return; } // "process" variable is guaranteed to be non-null at this point. ProcessAsync process = Process; using var cts = new CancellationTokenSource(_reasonableCoreShutdownTimeout); int?pid = await PidFile.TryReadAsync().ConfigureAwait(false); // If the cached PID is PID, then we own the process. if (pid.HasValue && (!onlyOwned || CachedPid == pid)) { Logger.LogDebug($"User is responsible for the daemon process with PID {pid}. Stop it."); try { bool isKilled = false; try { // Stop Bitcoin daemon using RPC "stop" command. // The command actually only initiates the bitcoind graceful shutdown procedure. // Our time budget for the bitcoind to stop is given by "ReasonableCoreShutdownTimeout". await RpcClient.StopAsync().ConfigureAwait(false); } catch (Exception ex) { Logger.LogWarning(ex); process.Kill(); isKilled = true; } if (!isKilled) { Logger.LogDebug($"Wait until the process is stopped."); await process.WaitForExitAsync(cts.Token).ConfigureAwait(false); } } finally { Logger.LogDebug($"Wait until the process is stopped."); process.Dispose(); Process = null; PidFile.TryDelete(); } } else { Logger.LogDebug("User is NOT responsible for the daemon process."); } Logger.LogDebug("<"); }
/// <summary> /// Stops bitcoin daemon process when PID file exists. /// </summary> /// <remarks>If there is not PID file, no process is stopped.</remarks> /// <param name="onlyOwned">Only stop if this node owns the process.</param> public async Task StopAsync(bool onlyOwned) { Logger.LogDebug($"> {nameof(onlyOwned)}={onlyOwned}"); if (Process is null) { Logger.LogDebug("< Process is null."); return; } ProcessAsync process = Process; // process is guaranteed to be non-null at this point. using var cts = new CancellationTokenSource(ReasonableCoreShutdownTimeout); int?pid = await PidFile.TryReadAsync().ConfigureAwait(false); // If the cached PID is PID, then we own the process. if (pid.HasValue && (!onlyOwned || CachedPid == pid)) { Logger.LogDebug($"User is responsible for the daemon process with PID {pid}. Stop it."); try { try { await RpcClient.StopAsync().ConfigureAwait(false); } catch (Exception ex) { Logger.LogWarning(ex); process.Kill(); } Logger.LogDebug($"Wait until the process is stopped."); await process.WaitForExitAsync(cts.Token).ConfigureAwait(false); } finally { Logger.LogDebug($"Wait until the process is stopped."); process.Dispose(); Process = null; PidFile.TryDelete(); } } else { Logger.LogDebug("User is NOT responsible for the daemon process."); } Logger.LogDebug("<"); }