mirror of
https://github.com/Qortal/qortal.git
synced 2025-04-01 17:55:54 +00:00
Update RestartNode.java
* Simplified logic * Improve logging * Ensure that streams are properly closed in the Process to avoid leaks * Optimized for readability, robustness, and scalability while maintaining the existing functionality.
This commit is contained in:
parent
8ffb0625a1
commit
42204a6205
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user