Fix servers not responding to SIGTERM and SIGINT
This commit is contained in:
parent
a3ddeaac9a
commit
64b19191db
|
@ -1,5 +1,7 @@
|
|||
package tc.oc.commons.core.restart;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.time.Duration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
@ -39,17 +41,23 @@ public class RequestRestartEvent {
|
|||
}
|
||||
|
||||
public Deferral defer(String deferrerName) {
|
||||
return defer(deferrerName, null);
|
||||
}
|
||||
|
||||
public Deferral defer(String deferrerName, @Nullable Duration predictedDelay) {
|
||||
logger.info("Restart deferred by " + deferrerName);
|
||||
Deferral deferral = new Deferral(deferrerName);
|
||||
Deferral deferral = new Deferral(deferrerName, predictedDelay);
|
||||
deferrals.add(deferral);
|
||||
return deferral;
|
||||
}
|
||||
|
||||
public class Deferral {
|
||||
private final String deferrerName;
|
||||
private final Duration predictedDelay;
|
||||
|
||||
public Deferral(String deferrerName) {
|
||||
public Deferral(String deferrerName, @Nullable Duration predictedDelay) {
|
||||
this.deferrerName = deferrerName;
|
||||
this.predictedDelay = predictedDelay;
|
||||
}
|
||||
|
||||
public RequestRestartEvent request() {
|
||||
|
@ -60,6 +68,10 @@ public class RequestRestartEvent {
|
|||
return deferrerName;
|
||||
}
|
||||
|
||||
public Duration predictedDelay() {
|
||||
return predictedDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow the deferred restart to proceed. After this method is called,
|
||||
* this object becomes useless and can be discarded.
|
||||
|
|
|
@ -4,6 +4,9 @@ import javax.annotation.Nullable;
|
|||
import javax.inject.Inject;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import tc.oc.commons.core.configuration.ConfigUtils;
|
||||
import tc.oc.commons.core.exception.ExceptionHandler;
|
||||
import tc.oc.minecraft.api.configuration.Configuration;
|
||||
|
@ -55,4 +58,11 @@ public class RestartConfiguration {
|
|||
public int kickLimit() {
|
||||
return config.getInt("kick-limit", Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restart the server when any of the given stop signals are received from the system.
|
||||
*/
|
||||
public Set<String> stopSignals() {
|
||||
return ConfigUtils.getStringSet(config, "stop-signals", Sets.newHashSet("INT", "TERM"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package tc.oc.commons.core.restart;
|
|||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
@ -17,6 +18,7 @@ import com.google.common.eventbus.EventBus;
|
|||
import com.google.common.eventbus.Subscribe;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import sun.misc.Signal;
|
||||
import tc.oc.api.docs.Server;
|
||||
import tc.oc.api.docs.virtual.ServerDoc;
|
||||
import tc.oc.api.minecraft.MinecraftService;
|
||||
|
@ -60,6 +62,7 @@ public class RestartManager implements PluginFacet, Tickable {
|
|||
this.eventBus = eventBus;
|
||||
this.threads = threads;
|
||||
this.startTime = Instant.now();
|
||||
onSignal(this.config.stopSignals());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -160,6 +163,15 @@ public class RestartManager implements PluginFacet, Tickable {
|
|||
}
|
||||
}
|
||||
|
||||
private void requestRestartInternal(Instant time, String reason, int priority) {
|
||||
logger.info("Restart requested at " + time +
|
||||
", with " + priority +
|
||||
" priority, because \"" + reason + '"');
|
||||
currentRequest = new RequestRestartEvent(logger, reason, priority, this::restartIfRequested);
|
||||
eventBus.post(currentRequest);
|
||||
restartIfRequested();
|
||||
}
|
||||
|
||||
public ListenableFuture<?> cancelRestart() {
|
||||
if(this.isRestartRequested()) {
|
||||
return minecraftService.updateLocalServer(new ServerDoc.Restart() {
|
||||
|
@ -202,12 +214,7 @@ public class RestartManager implements PluginFacet, Tickable {
|
|||
}
|
||||
|
||||
if(newTime != null) {
|
||||
logger.info("Restart requested at " + newTime +
|
||||
", with " + newPriority +
|
||||
" priority, because \"" + newReason + '"');
|
||||
currentRequest = new RequestRestartEvent(logger, newReason, newPriority, this::restartIfRequested);
|
||||
eventBus.post(currentRequest);
|
||||
restartIfRequested();
|
||||
requestRestartInternal(newTime, newReason, newPriority);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -236,4 +243,28 @@ public class RestartManager implements PluginFacet, Tickable {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void onSignal(Collection<String> signals) {
|
||||
signals.stream()
|
||||
.map(Signal::new)
|
||||
.forEach(signal -> Signal.handle(signal, s -> {
|
||||
requestRestartInternal(Instant.now(), "Received signal " + s.getName() + " (" + s.getNumber() + ") from system", Integer.MAX_VALUE);
|
||||
try {
|
||||
Thread.sleep(currentRequest.deferrals()
|
||||
.stream()
|
||||
.filter(deferral -> deferral.predictedDelay() != null)
|
||||
.map(RequestRestartEvent.Deferral::predictedDelay)
|
||||
.findFirst()
|
||||
.orElse(Duration.ZERO)
|
||||
.toMillis() + 1L);
|
||||
} catch(InterruptedException e) {
|
||||
if(!minecraftServer.isStopping()) {
|
||||
logger.severe(s.getName() + " signal is unable to wait for restart");
|
||||
}
|
||||
}
|
||||
if(!restartIfRequested() && !minecraftServer.isStopping()) {
|
||||
minecraftServer.stop();
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -142,7 +142,7 @@ public class RestartListener implements PluginFacet, Listener {
|
|||
public void onRequestRestart(RequestRestartEvent event) {
|
||||
if(!server.isSuspended()) {
|
||||
logger.info("Deferring restart");
|
||||
deferral = event.defer(getClass().getName());
|
||||
deferral = event.defer(getClass().getName(), config.time());
|
||||
checkCountdown(mm.needCurrentMatch());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue