CloudNet icon indicating copy to clipboard operation
CloudNet copied to clipboard

Fix: Minestom does not properly shut down

Open GiantTreeLP opened this issue 1 year ago • 1 comments

Motivation

Minestom is a very lightweight framework for implementing specialized Minecraft servers.
Especially when the full implementation or behavior of vanilla Minecraft is not needed, Minestom offers a way to run services with very little resources.

One issue that arised in conjunction with CloudNet is that services implemented using Minestom would not properly stop. Minestom would shut down and the service would get unregistered from CloudNet but the processes would be kept running.

Modification

This pull request first exposes and then properly uses the built-in methods for closing resources that prevent the Wrapper process from exiting.
Mainly, this is facilitated by shutting down components that hold thread pools which in turn hold non-daemon threads that specifically prevent the JVM from shutting down.

Result

Services using the Minestom framework now properly shut down and allow CloudNet to advance to the next lifecycle steps.
The changes from this PR can also be used to improve the quality of other implementations.

Other context

Fixes #1304

GiantTreeLP avatar Dec 06 '23 18:12 GiantTreeLP

If you want to test these changes, I have developed a simple minimal Minestom implementation:

package com.github.gianttree.miniminestom

import net.minestom.server.MinecraftServer
import net.minestom.server.timer.TaskSchedule
import java.util.logging.ConsoleHandler
import java.util.logging.Level
import java.util.logging.Logger

fun main() {

    val logger = Logger.getLogger("MiniMinestom")
    logger.level = Level.ALL
    logger.useParentHandlers = false
    logger.addHandler(ConsoleHandler().apply {
        level = Level.ALL
    })

    logger.info("Starting MiniMinestom...")

    val hostAddress = System.getProperty("service.bind.host")
    logger.fine("Host address: $hostAddress")
    if (hostAddress == null) {
        logger.severe("Host address not set!")
        return
    }

    val hostPort = Integer.getInteger("service.bind.port")
    logger.fine("Host port: $hostPort")
    if (hostPort == null) {
        logger.severe("Host port not set!")
        return
    }

    val server = MinecraftServer.init()
    logger.fine("Server initialized")

    val scheduler = MinecraftServer.getSchedulerManager()
    scheduler.scheduleTask(
        {
            logger.info("Stopping server")
            MinecraftServer.stopCleanly()
        },
        TaskSchedule.seconds(2),
        TaskSchedule.stop()
    )

    logger.info("Starting server")
    server.start(hostAddress, hostPort)
    logger.info("Server started")
}

GiantTreeLP avatar Dec 06 '23 18:12 GiantTreeLP

Closed in favor of #1338

0utplay avatar May 16 '24 14:05 0utplay