This commit is contained in:
Brian Neumann-Fopiano
2026-08-02 04:16:06 -04:00
parent a8217b42e9
commit 10b2363226
13 changed files with 118 additions and 83 deletions
@@ -408,10 +408,27 @@ public final class IrisModdedChunkGenerator extends ChunkGenerator {
}
private void requireCompletedShutdown(Engine current) {
if (current != null && current.isClosing() && !current.isClosed()) {
throw new IllegalStateException("Iris generator '" + dimensionKey
+ "' cannot bind while its previous engine shutdown remains incomplete");
if (current == null || !current.isClosing() || current.isClosed()) {
return;
}
// closing && !closed is usually a TRANSIENT seal: hotloadComplex/hotloadSilently set closing while
// they swap the runtime and clear it on completion. Wait the transition out instead of crashing the
// chunk pipeline; only a seal that never resolves is a genuine incomplete shutdown.
long deadline = System.currentTimeMillis() + 30_000L;
while (System.currentTimeMillis() < deadline && !current.hasFailed()) {
if (current.isClosed() || !current.isClosing()) {
return;
}
try {
Thread.sleep(10L);
} catch (InterruptedException interrupted) {
Thread.currentThread().interrupt();
break;
}
}
throw new IllegalStateException("Iris generator '" + dimensionKey
+ "' cannot bind while its previous engine shutdown remains incomplete"
+ (current.hasFailed() ? " (engine failed)" : " (waited 30s)"));
}
private void requireBindingAllowed() {
@@ -54,6 +54,7 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
private static final long ADAPTIVE_RECOVERY_INTERVAL = 64L;
private static final long FINAL_SAVE_TIMEOUT_MILLIS = 10_000L;
private static final long FINAL_SAVE_POLL_MILLIS = 50L;
private static final AtomicBoolean SERVER_DEAD_LOGGED = new AtomicBoolean();
private final ServerLevel level;
private final Engine engine;
@@ -358,6 +359,16 @@ public final class ModdedPregenMethod implements PregeneratorMethod {
}
private void generateChunkAsync(int x, int z, PregenListener listener) {
// A stopped server executes submitted tasks inline and its chunk futures never complete; without
// this abort the pregen thread spins hot against the dead chunk source until the JVM dies.
if (level.getServer().isStopped() || !level.getServer().isRunning()) {
if (SERVER_DEAD_LOGGED.compareAndSet(false, true)) {
LOGGER.error("Iris pregen aborting: the server is no longer running (dim={})", level.dimension().identifier());
}
listener.onChunkFailed(x, z);
ModdedPregenJob.stop();
return;
}
listener.onChunkGenerating(x, z);
try {
synchronized (permitMonitor) {