More robust stop signal configuration
This commit is contained in:
parent
0caea52598
commit
99ae043580
|
@ -1,7 +1,5 @@
|
|||
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;
|
||||
|
@ -41,23 +39,17 @@ 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, predictedDelay);
|
||||
Deferral deferral = new Deferral(deferrerName);
|
||||
deferrals.add(deferral);
|
||||
return deferral;
|
||||
}
|
||||
|
||||
public class Deferral {
|
||||
private final String deferrerName;
|
||||
private final Duration predictedDelay;
|
||||
|
||||
public Deferral(String deferrerName, @Nullable Duration predictedDelay) {
|
||||
public Deferral(String deferrerName) {
|
||||
this.deferrerName = deferrerName;
|
||||
this.predictedDelay = predictedDelay;
|
||||
}
|
||||
|
||||
public RequestRestartEvent request() {
|
||||
|
@ -68,10 +60,6 @@ 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.
|
||||
|
|
|
@ -63,6 +63,20 @@ public class RestartConfiguration {
|
|||
* 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"));
|
||||
return ConfigUtils.getStringSet(config, "stop-signal.triggers", Sets.newHashSet("INT", "TERM"));
|
||||
}
|
||||
|
||||
/**
|
||||
* The priority that stop signals will restart the server with.
|
||||
*/
|
||||
public Integer stopSignalPriority() {
|
||||
return config.getInt("stop-signal.priority", Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximum time the server will wait for deferals to resume before forcing a restart.
|
||||
*/
|
||||
public Duration stopSignalTimeout() {
|
||||
return ConfigUtils.getDuration(config, "stop-signal.timeout", Duration.ofHours(6));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import java.util.Collection;
|
|||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -62,7 +63,6 @@ public class RestartManager implements PluginFacet, Tickable {
|
|||
this.eventBus = eventBus;
|
||||
this.threads = threads;
|
||||
this.startTime = Instant.now();
|
||||
onSignal(this.config.stopSignals());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -85,6 +85,8 @@ public class RestartManager implements PluginFacet, Tickable {
|
|||
TimeUnit.MILLISECONDS
|
||||
);
|
||||
}
|
||||
// Enable listeners for stop signals
|
||||
onSignal(this.config.stopSignals());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -248,20 +250,35 @@ public class RestartManager implements PluginFacet, Tickable {
|
|||
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);
|
||||
String reason = "Received signal " + s.getName() + " (" + s.getNumber() + ") from system";
|
||||
int priority = config.stopSignalPriority();
|
||||
try {
|
||||
Thread.sleep(currentRequest.deferrals()
|
||||
.stream()
|
||||
.filter(deferral -> deferral.predictedDelay() != null)
|
||||
.map(RequestRestartEvent.Deferral::predictedDelay)
|
||||
.findFirst()
|
||||
.orElse(Duration.ZERO)
|
||||
.toMillis() + 1L);
|
||||
// Attempt to send restart request to the api
|
||||
requestRestart(reason, priority).get();
|
||||
// Wait for restart to sync back to the server
|
||||
boolean success = true;
|
||||
Instant start = Instant.now();
|
||||
while(currentRequest == null || !currentRequest.reason().equals(reason)) {
|
||||
Thread.sleep(Duration.ofSeconds(1).toMillis());
|
||||
if(Duration.between(start, Instant.now()).getSeconds() > 5) {
|
||||
logger.warning("Unable to request a " + signal.getName() + " signal restart to the api");
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
if(!success) throw new InterruptedException();
|
||||
} catch(InterruptedException | ExecutionException e) {
|
||||
// Fallback to sending the request via local server events
|
||||
requestRestartInternal(Instant.now(), reason, priority);
|
||||
}
|
||||
try {
|
||||
// Sleep until maximum timeout before forcibly stopping the server
|
||||
Thread.sleep(config.stopSignalTimeout().toMillis());
|
||||
} catch(InterruptedException e) {
|
||||
if(!minecraftServer.isStopping()) {
|
||||
logger.severe(s.getName() + " signal is unable to wait for restart");
|
||||
}
|
||||
}
|
||||
// Stop the server is all other restart attempts have failed
|
||||
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(), config.time());
|
||||
deferral = event.defer(getClass().getName());
|
||||
checkCountdown(mm.needCurrentMatch());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue