Skip to content

Commit e012273

Browse files
0utplayderklaro
andauthored
fix: handle SIGHUP in launcher-patcher to prevent exits before updating (#1641)
### Motivation The launcher-patcher tries to update the launcher.jar after the node & launcher exit. This process did not work when `screen` or `tmux` was used to start the launcher due to the fact that they send a `SIGHUG` signal and the JVM handles the signal and stops the still running (waiting) launcher-patcher. This required users to download the launcher themselves when we did changes to the launcher. ### Modification Introduced a handler for `SIGHUP` in the launcher-patcher that ignores the signal. Furthermore, this introduces a 5 second timeout when waiting for the launcher to exit before running the patcher as the launcher should not take that long to stop and to prevent replacing the next running launcher instance getting replaced while running. ### Result Launcher updates are properly working when using `screen` or `tmux` --------- Co-authored-by: Pasqual Koschmieder <git@derklaro.dev>
1 parent 5b74133 commit e012273

1 file changed

Lines changed: 34 additions & 13 deletions

File tree

launcher/patcher/src/main/java/eu/cloudnetservice/launcher/patcher/CloudNetLauncherPatcher.java

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,40 +17,61 @@
1717
package eu.cloudnetservice.launcher.patcher;
1818

1919
import java.io.IOException;
20+
import java.io.PrintStream;
2021
import java.io.UncheckedIOException;
2122
import java.nio.file.Files;
2223
import java.nio.file.Path;
2324
import java.nio.file.StandardCopyOption;
25+
import java.util.concurrent.TimeUnit;
2426
import lombok.NonNull;
27+
import sun.misc.Signal;
28+
import sun.misc.SignalHandler;
2529

2630
public final class CloudNetLauncherPatcher {
2731

2832
public static void main(@NonNull String[] args) {
29-
// validate that we got all required args to run (<pid> <old launcher> <new launcher>)
33+
try {
34+
// the jvm has a signal handler for SIGHUP, which exists the jvm when received
35+
// tmux and screen use SIGHUP to signal the process that the session closed; however,
36+
// this shouldn't prevent the patching process from running anyway
37+
Signal.handle(new Signal("HUP"), SignalHandler.SIG_IGN);
38+
} catch (Throwable throwable) {
39+
printf(System.err, "Unable to register signal handler: %s", throwable.getMessage());
40+
}
41+
42+
// validate that we got all required args to run (<pid> <launcher path> <new launcher path>)
3043
if (args.length == 3) {
3144
var launcherPid = Long.parseLong(args[0]);
32-
var oldLauncherPath = Path.of(args[1]);
45+
var launcherPath = Path.of(args[1]);
3346
var newLauncherPath = Path.of(args[2]);
34-
// just for debug reasons
35-
// CHECKSTYLE.OFF: Launcher has no proper logger
36-
System.out.printf("Picked up options: %s -> %s (pid: %d)%n", oldLauncherPath, newLauncherPath, launcherPid);
37-
// CHECKSTYLE.ON
47+
printf(System.out, "Picked up options:");
48+
printf(System.out, " - Launcher PID: %d", launcherPid);
49+
printf(System.out, " - Launcher Path: %s", launcherPath);
50+
printf(System.out, " - New Launcher Path: %s", newLauncherPath);
51+
3852
// wait for the process to terminate by joining it (to block the current thread)
39-
ProcessHandle.of(launcherPid).ifPresent(handle -> handle.onExit().join());
40-
// the process doesn't exist or terminated - run the updater now
41-
// CHECKSTYLE.OFF: Launcher has no proper logger
42-
System.out.printf("Running patcher on file %s%n", oldLauncherPath);
43-
// CHECKSTYLE.ON
44-
replaceOldLauncher(oldLauncherPath, newLauncherPath);
53+
ProcessHandle.of(launcherPid).ifPresent(handle -> handle.onExit()
54+
.orTimeout(5, TimeUnit.SECONDS)
55+
.exceptionally(__ -> {
56+
printf(System.err, "Launcher process did not terminate in time, running patcher anyway");
57+
return null;
58+
})
59+
.join());
60+
61+
printf(System.out, "Copying new launcher file...");
62+
replaceOldLauncher(launcherPath, newLauncherPath);
4563
}
4664
}
4765

4866
private static void replaceOldLauncher(@NonNull Path oldPath, @NonNull Path newPath) {
4967
try {
50-
// move the new file to the location of the old file
5168
Files.copy(newPath, oldPath, StandardCopyOption.REPLACE_EXISTING);
5269
} catch (IOException exception) {
5370
throw new UncheckedIOException(exception);
5471
}
5572
}
73+
74+
private static void printf(@NonNull PrintStream target, @NonNull String format, @NonNull Object... args) {
75+
target.printf(format + "%n", args);
76+
}
5677
}

0 commit comments

Comments
 (0)