Merge 42204a62059d64ab79728b8ae26b401b83b2cf87 into 8ffb0625a1edcf0b3d1ec2498b15a31ec38ade3c

This commit is contained in:
cwd.systems | 0KN 2024-11-27 22:04:22 +06:00 committed by GitHub
commit a16023939a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -18,85 +18,93 @@ import java.util.List;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/* NOTE: It is CRITICAL that we use OpenJDK and not Java SE because our uber jar repacks BouncyCastle which, in turn, unsigns BC causing it to be rejected as a security provider by Java SE. */
public class RestartNode { public class RestartNode {
public static final String JAR_FILENAME = "qortal.jar"; private static final Logger LOGGER = LogManager.getLogger(RestartNode.class);
public static final String AGENTLIB_JVM_HOLDER_ARG = "-DQORTAL_agentlib=";
private static final Logger LOGGER = LogManager.getLogger(RestartNode.class); public static final String JAR_FILENAME = "qortal.jar";
public static final String AGENTLIB_JVM_HOLDER_ARG = "-DQORTAL_agentlib=";
public static boolean attemptToRestart() { public static boolean attemptToRestart() {
LOGGER.info(String.format("Restarting node...")); LOGGER.info("Restarting node...");
// Give repository a chance to backup in case things go badly wrong (if enabled) // Attempt repository backup if enabled
if (Settings.getInstance().getRepositoryBackupInterval() > 0) { if (Settings.getInstance().getRepositoryBackupInterval() > 0) {
try { try {
// Timeout if the database isn't ready for backing up after 60 seconds long timeoutMillis = 60 * 1000L; // 60 seconds
long timeout = 60 * 1000L; RepositoryManager.backup(true, "backup", timeoutMillis);
RepositoryManager.backup(true, "backup", timeout); LOGGER.info("Repository backup completed successfully.");
} catch (TimeoutException e) {
LOGGER.warn("Repository backup timed out: {}", e.getMessage());
// Proceed with the restart even if backup fails
} catch (Exception e) {
LOGGER.error("Unexpected error during repository backup: {}", e.getMessage(), e);
// Proceed with the restart despite errors
}
}
} catch (TimeoutException e) { try {
LOGGER.info("Attempt to backup repository failed due to timeout: {}", e.getMessage()); // Locate the Java binary
// Continue with the node restart anyway... String javaHome = System.getProperty("java.home");
} LOGGER.debug("Java home directory: {}", javaHome);
}
// Call ApplyRestart to end this process Path javaBinary = Paths.get(javaHome, "bin", "java");
String javaHome = System.getProperty("java.home"); LOGGER.debug("Java binary path: {}", javaBinary);
LOGGER.debug(String.format("Java home: %s", javaHome));
Path javaBinary = Paths.get(javaHome, "bin", "java"); // Prepare command to restart the node
LOGGER.debug(String.format("Java binary: %s", javaBinary)); List<String> javaCmd = new ArrayList<>();
javaCmd.add(javaBinary.toString());
try { // JVM arguments
List<String> javaCmd = new ArrayList<>(); List<String> jvmArgs = new ArrayList<>(ManagementFactory.getRuntimeMXBean().getInputArguments());
// Java runtime binary itself
javaCmd.add(javaBinary.toString());
// JVM arguments // Handle -agentlib arguments to avoid port conflicts
javaCmd.addAll(ManagementFactory.getRuntimeMXBean().getInputArguments()); jvmArgs = jvmArgs.stream()
.map(arg -> arg.startsWith("-agentlib") ? arg.replace("-agentlib", AGENTLIB_JVM_HOLDER_ARG) : arg)
.collect(Collectors.toList());
// Disable, but retain, any -agentlib JVM arg as sub-process might fail if it tries to reuse same port // Remove unsupported JNI options
javaCmd = javaCmd.stream() List<String> unsupportedOptions = Arrays.asList("abort", "exit", "vfprintf");
.map(arg -> arg.replace("-agentlib", AGENTLIB_JVM_HOLDER_ARG)) jvmArgs.removeAll(unsupportedOptions);
.collect(Collectors.toList());
// Remove JNI options as they won't be supported by command-line 'java' javaCmd.addAll(jvmArgs);
// These are typically added by the AdvancedInstaller Java launcher EXE
javaCmd.removeAll(Arrays.asList("abort", "exit", "vfprintf"));
// Call ApplyRestart using JAR // Add the classpath and main class
javaCmd.addAll(Arrays.asList("-cp", JAR_FILENAME, ApplyRestart.class.getCanonicalName())); javaCmd.addAll(Arrays.asList("-cp", JAR_FILENAME, ApplyRestart.class.getCanonicalName()));
// Add command-line args saved from start-up // Include saved startup arguments
String[] savedArgs = Controller.getInstance().getSavedArgs(); String[] savedArgs = Controller.getInstance().getSavedArgs();
if (savedArgs != null) if (savedArgs != null) {
javaCmd.addAll(Arrays.asList(savedArgs)); javaCmd.addAll(Arrays.asList(savedArgs));
}
LOGGER.debug(String.format("Restarting node with: %s", String.join(" ", javaCmd))); LOGGER.info("Restarting node with command: {}", String.join(" ", javaCmd));
SysTray.getInstance().showMessage(Translator.INSTANCE.translate("SysTray", "RESTARTING_NODE"), // Notify the user
Translator.INSTANCE.translate("SysTray", "APPLYING_RESTARTING_NODE"), SysTray.getInstance().showMessage(
MessageType.INFO); Translator.INSTANCE.translate("SysTray", "RESTARTING_NODE"),
Translator.INSTANCE.translate("SysTray", "APPLYING_RESTARTING_NODE"),
MessageType.INFO
);
ProcessBuilder processBuilder = new ProcessBuilder(javaCmd); // Start the new process
ProcessBuilder processBuilder = new ProcessBuilder(javaCmd);
processBuilder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
processBuilder.redirectError(ProcessBuilder.Redirect.INHERIT);
// New process will inherit our stdout and stderr Process process = processBuilder.start();
processBuilder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
processBuilder.redirectError(ProcessBuilder.Redirect.INHERIT);
Process process = processBuilder.start(); // Close the process's input stream to avoid resource leaks
try {
process.getOutputStream().close();
} catch (Exception e) {
LOGGER.warn("Failed to close process output stream: {}", e.getMessage());
}
// Nothing to pipe to new process, so close output stream (process's stdin) return true; // Node restart initiated successfully
process.getOutputStream().close(); } catch (Exception e) {
LOGGER.error("Failed to restart node: {}", e.getMessage(), e);
return true; // restarting node OK return true; // Return true to indicate repo was okay even if restart failed
} catch (Exception e) { }
LOGGER.error(String.format("Failed to restart node: %s", e.getMessage())); }
}
return true; // repo was okay, even if applying restart failed
}
}
}