Add integrated server watchdog

This commit is contained in:
embeddedt 2023-04-12 16:05:08 -04:00
parent 3b56f00b82
commit 10149e9f87
No known key found for this signature in database
GPG Key ID: A69433EC199B5613
3 changed files with 78 additions and 0 deletions

View File

@ -20,11 +20,15 @@ import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.ModContainer;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
import net.minecraftforge.fml.event.server.FMLServerStartedEvent;
import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
import net.minecraftforge.fml.network.NetworkEvent;
import org.embeddedt.modernfix.core.ModernFixMixinPlugin;
import org.embeddedt.modernfix.core.config.ModernFixConfig;
import org.embeddedt.modernfix.load.LoadEvents;
import org.embeddedt.modernfix.packet.EntityIDSyncPacket;
import org.embeddedt.modernfix.screen.DeferredLevelLoadingScreen;
import org.embeddedt.modernfix.world.IntegratedWatchdog;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Field;
@ -219,4 +223,13 @@ public class ModernFixClient {
context.get().setPacketHandled(true);
}
@SubscribeEvent
public void onServerStarted(FMLServerStartingEvent event) {
if(ModernFixConfig.INTEGRATED_SERVER_WATCHDOG.get()) {
IntegratedWatchdog watchdog = new IntegratedWatchdog(event.getServer());
watchdog.start();
}
}
}

View File

@ -26,6 +26,7 @@ public class ModernFixConfig {
public static ForgeConfigSpec.BooleanValue ENABLE_DEBUG_RELOADER;
public static ForgeConfigSpec.BooleanValue REBUILD_BLOCKSTATES_ASYNC;
public static ForgeConfigSpec.BooleanValue INTEGRATED_SERVER_WATCHDOG;
public static Set<ResourceLocation> jeiPluginBlacklist;
@ -43,6 +44,9 @@ public class ModernFixConfig {
REBUILD_BLOCKSTATES_ASYNC = COMMON_BUILDER
.comment("Rebuild blockstate cache asynchronously. Should work with most mods, but can be disabled.")
.define("rebuild_blockstate_cache_async", true);
INTEGRATED_SERVER_WATCHDOG = COMMON_BUILDER
.comment("Automatically output a thread dump if the integrated server spends too long on one tick")
.define("integrated_server_watchdog", true);
}
static {

View File

@ -0,0 +1,61 @@
package org.embeddedt.modernfix.world;
import net.minecraft.DefaultUncaughtExceptionHandlerWithName;
import net.minecraft.Util;
import net.minecraft.server.MinecraftServer;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.util.concurrent.TimeUnit;
public class IntegratedWatchdog extends Thread {
private static final Logger LOGGER = LogManager.getLogger();
private final MinecraftServer server;
private static final long MAX_TICK_DELTA = 40*1000;
public IntegratedWatchdog(MinecraftServer server) {
this.server = server;
this.setDaemon(true);
this.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandlerWithName(LOGGER));
this.setName("ModernFix integrated server watchdog");
}
public void run() {
while(server.isRunning()) {
long nextTick = this.server.getNextTickTime();
long curTime = Util.getMillis();
if((curTime - nextTick) > MAX_TICK_DELTA) {
LOGGER.error("A single server tick has taken {}, more than {} milliseconds", (nextTick - curTime), MAX_TICK_DELTA);
ThreadMXBean threadmxbean = ManagementFactory.getThreadMXBean();
ThreadInfo[] athreadinfo = threadmxbean.dumpAllThreads(true, true);
StringBuilder sb = new StringBuilder();
sb.append("Thread Dump:\n");
for(ThreadInfo threadinfo : athreadinfo) {
sb.append(threadinfo);
StackTraceElement[] elements = threadinfo.getStackTrace();
if(elements.length > 8) {
sb.append("extended trace:\n");
for(int i = 8; i < elements.length; i++) {
sb.append("\tat ");
sb.append(elements[i]);
sb.append('\n');
}
}
sb.append('\n');
}
LOGGER.error(sb);
nextTick = 0;
curTime = 0;
}
try {
Thread.sleep(nextTick + MAX_TICK_DELTA - curTime);
} catch(InterruptedException ignored) {
}
}
}
}