Repository navigation
Conversation
|
Please provide an example of such an exception that had a much larger blast radius |
006536d to
51a2449
Compare
|
Good question. Here is a concrete example from #32 (the 2500-bot run): Description: Exception in server tick loop
java.util.concurrent.CompletionException: java.lang.NullPointerException: Cannot read field "nearbyPlayers" because the return value of "...moonrise$getChunkData()" is null
at java.base/java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1807)
Caused by: java.lang.NullPointerException: ...
at io.multipaper.shreddedpaper.threading.ShreddedPaperEntityTicker.processTrackQueue(ShreddedPaperEntityTicker.java:44)
at io.multipaper.shreddedpaper.threading.ShreddedPaperChunkTicker.lambda$processTrackQueueInParallel$6(ShreddedPaperChunkTicker.java:71)The exception comes from the You're right that my "blast radius" wording was too strong. This isn't meant to replace the root-cause fix in #32; I kept it symmetrical with Let me know what you think. |
…rallel Unlike tickRegion, which catches exceptions and marks a chunk-system crash, the parallel tracked-entity and packet-flush futures had no .exceptionally() at all. An exception there propagates uncaught through ServerChunkCache.tick -> ServerLevel.tickAsync -> MinecraftServer's future.join(), unwinding tickChildren before the other level futures are joined or the rest of the tick runs. A real case is MultiPaper#32, where an NPE from processTrackQueue surfaced as a CompletionException and crashed the tick loop. Add matching .exceptionally() handlers so a failure in these paths is logged at the source and goes through the same controlled chunk-system crash path as tickRegion. Include the world name in both messages so the failure points at the affected level.
51a2449 to
1c60857
Compare
Summary
Found while investigating #49 (unrelated, reporting separately since it's a distinct bug).
tickRegion()isolates any exception to the single failing region: it logs and callsmoonrise$setChunkSystemCrash(...), letting the rest of the tick continue.processTrackQueueInParallel()andflushQueueInParallel(), one method away in the same file, have no.exceptionally()at all.Traced the future chain up through
ServerChunkCache.tick()->ServerLevel.tickAsync()->MinecraftServer's per-levelfuture.join()(unguarded by any try/catch at that point). An exception thrown here is not silently dropped: it propagates uncaught throughjoin()and unwindstickChildrenbefore the other level futures are joined or the rest of the tick runs. A real example is #32: an NPE fromprocessTrackQueue(entity removed concurrently, somoonrise$getChunkData()is null) surfaced as aCompletionExceptionand crashed the tick loop. Withprocess-track-queue-in-parallel: false, the same NPE is thrown inside_tickRegionand caught bytickRegion()'s handler, so the handling currently depends on the optimization flag.This adds matching
.exceptionally()handlers to both methods, so a failure here is logged with the failing world and goes through the same controlled chunk-system crash path astickRegion()instead of unwindingjoin()directly. It does not replace the root-cause fix in #32; theflushQueueInParallelhalf is symmetry and defence.Test plan
./gradlew :shreddedpaper-server:compileJava)