Wait for clients to disconnect (within reasonable timeframe) before initiating server shutdown

This commit is contained in:
DBotThePony 2024-05-22 19:04:05 +07:00
parent 8ef6bead2c
commit 5769cff60b
Signed by: DBot
GPG Key ID: DCC23B5715498507

View File

@ -17,6 +17,7 @@ import java.io.Closeable
import java.net.SocketAddress import java.net.SocketAddress
import java.util.* import java.util.*
import java.util.concurrent.CopyOnWriteArrayList import java.util.concurrent.CopyOnWriteArrayList
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.locks.ReentrantLock import java.util.concurrent.locks.ReentrantLock
import kotlin.concurrent.withLock import kotlin.concurrent.withLock
@ -112,15 +113,18 @@ class ServerChannels(val server: StarboundServer) : Closeable {
val channel = ServerBootstrap().channel(LocalServerChannel::class.java).group(Connection.NIO_POOL).childHandler(object : ChannelInitializer<Channel>() { val channel = ServerBootstrap().channel(LocalServerChannel::class.java).group(Connection.NIO_POOL).childHandler(object : ChannelInitializer<Channel>() {
override fun initChannel(ch: Channel) { override fun initChannel(ch: Channel) {
LOGGER.info("Incoming connection from ${ch.remoteAddress()}") lock.withLock {
if (isClosed) return
LOGGER.info("Incoming connection from ${ch.remoteAddress()}")
try { try {
val connection = ServerConnection(server, ConnectionType.MEMORY) val connection = ServerConnection(server, ConnectionType.MEMORY)
connections.add(connection) connections.add(connection)
connection.bind(ch) connection.bind(ch)
} catch (err: Throwable) { } catch (err: Throwable) {
LOGGER.error("Error while accepting new connection from ${ch.remoteAddress()}", err) LOGGER.error("Error while accepting new connection from ${ch.remoteAddress()}", err)
ch.close() ch.close()
}
} }
} }
}).bind(LocalAddress.ANY).syncUninterruptibly() }).bind(LocalAddress.ANY).syncUninterruptibly()
@ -141,15 +145,18 @@ class ServerChannels(val server: StarboundServer) : Closeable {
lock.withLock { lock.withLock {
val channel = ServerBootstrap().channel(NioServerSocketChannel::class.java).group(Connection.NIO_POOL).childHandler(object : ChannelInitializer<Channel>() { val channel = ServerBootstrap().channel(NioServerSocketChannel::class.java).group(Connection.NIO_POOL).childHandler(object : ChannelInitializer<Channel>() {
override fun initChannel(ch: Channel) { override fun initChannel(ch: Channel) {
LOGGER.info("Incoming connection from ${ch.remoteAddress()}") lock.withLock {
if (isClosed) return
LOGGER.info("Incoming connection from ${ch.remoteAddress()}")
try { try {
val connection = ServerConnection(server, ConnectionType.NETWORK) val connection = ServerConnection(server, ConnectionType.NETWORK)
connections.add(connection) connections.add(connection)
connection.bind(ch) connection.bind(ch)
} catch (err: Throwable) { } catch (err: Throwable) {
LOGGER.error("Error while accepting new connection from ${ch.remoteAddress()}", err) LOGGER.error("Error while accepting new connection from ${ch.remoteAddress()}", err)
ch.close() ch.close()
}
} }
} }
}).bind(localAddress).syncUninterruptibly() }).bind(localAddress).syncUninterruptibly()
@ -168,9 +175,18 @@ class ServerChannels(val server: StarboundServer) : Closeable {
override fun close() { override fun close() {
lock.withLock { lock.withLock {
if (isClosed) return if (isClosed) return
isClosed = true
connections.forEach { it.disconnect("Server shutting down") }
channels.forEach { it.channel().close() } channels.forEach { it.channel().close() }
connections.forEach { it.disconnect("Server shutting down") }
// aeugh
connections.forEach {
if (!it.waitDisconnect(2L, TimeUnit.SECONDS)) {
LOGGER.warn("Giving up waiting for $it to disconnect")
}
}
channels.clear() channels.clear()
connections.clear() connections.clear()
} }