1
0
Fork 1
mirror of https://gitlab.com/mangadex-pub/mangadex_at_home.git synced 2024-01-19 02:48:37 +00:00

Fix graceful shutdown

This commit is contained in:
carbotaniuman 2021-02-11 09:11:03 -06:00
parent e246924b57
commit d1d7fcca7f
5 changed files with 41 additions and 31 deletions

View file

@ -23,7 +23,7 @@
# The size in mebibytes of the cache
# You can use megabytes instead in a pinch,
# but just know the two are **NOT** the same.
max_cache_size_in_mebibytes: 1024
max_cache_size_in_mebibytes: 0
# Optional settings for fancy geoip analytics
metrics_settings:

View file

@ -32,7 +32,11 @@ object Main {
@JvmStatic
fun main(args: Array<String>) {
CommandLine(ClientArgs()).execute(*args)
try {
CommandLine(ClientArgs()).execute(*args)
} catch (e: Throwable) {
LOGGER.error(e) { "Critical Error " }
}
}
fun dieWithError(e: Throwable): Nothing {

View file

@ -175,8 +175,14 @@ class MangaDexClient(private val settingsFile: File, databaseFile: File, cacheFo
storage.maxSize = (newSettings.maxCacheSizeInMebibytes * 1024 * 1024 * 0.95).toLong()
stopImageServer()
startImageServer()
if (imageServer != null) {
stopImageServer()
}
try {
startImageServer()
} catch (e: Exception) {
LOGGER.warn(e) { "Error starting the image server" }
}
} catch (e: UnrecognizedPropertyException) {
LOGGER.warn { "Settings file is invalid: '$e.propertyName' is not a valid setting" }
} catch (e: JsonProcessingException) {
@ -189,8 +195,8 @@ class MangaDexClient(private val settingsFile: File, databaseFile: File, cacheFo
}
private fun validateSettings(settings: ClientSettings) {
if (settings.maxCacheSizeInMebibytes < 1024) {
throw ClientSettingsException("Config Error: Invalid max cache size, must be >= 1024 MiB (1GiB)")
if (settings.maxCacheSizeInMebibytes < 20480) {
throw ClientSettingsException("Config Error: Invalid max cache size, must be >= 20480 MiB (20 GiB)")
}
fun isSecretValid(clientSecret: String): Boolean {

View file

@ -58,7 +58,7 @@ object Shutdown : State()
data class GracefulStop(
val lastRunning: Running,
val counts: Int = 0,
val nextState: State = Uninitialized,
val nextState: State,
val action: () -> Unit = {}
) : State()
@ -193,7 +193,7 @@ class ServerManager(
if (settings.serverSettings.maxMebibytesPerHour != 0L && settings.serverSettings.maxMebibytesPerHour * 1024 * 1024 /* MiB to bytes */ < currentBytesSent) {
LOGGER.info { "Stopping image server as hourly bandwidth limit reached" }
this.state = GracefulStop(lastRunning = state)
this.state = GracefulStop(lastRunning = state, nextState = Uninitialized)
} else {
pingControl()
}
@ -245,7 +245,7 @@ class ServerManager(
if (!state.settings.logicalEqual(newSettings)) {
LOGGER.info { "Doing internal restart of HTTP server to refresh settings" }
this.state = GracefulStop(lastRunning = state) {
this.state = GracefulStop(lastRunning = state, nextState = Uninitialized) {
loginAndStartServer()
}
}

View file

@ -77,9 +77,9 @@ sealed class NettyTransport(threads: Int) {
)
fun shutdownGracefully() {
bossGroup.shutdownGracefully()
workerGroup.shutdownGracefully()
executor.shutdownGracefully()
bossGroup.shutdownGracefully().sync()
workerGroup.shutdownGracefully().sync()
executor.shutdownGracefully().sync()
}
private class NioTransport(threads: Int) : NettyTransport(threads) {
@ -111,21 +111,25 @@ sealed class NettyTransport(threads: Int) {
LOGGER.info { "Choosing a transport using $threadsToUse threads" }
if (name.startsWith("linux")) {
if (IOUring.isAvailable()) {
LOGGER.info { "Using IOUring transport" }
return IOUringTransport(threadsToUse)
} else {
LOGGER.info(IOUring.unavailabilityCause()) {
"IOUring transport not available"
if (!SystemPropertyUtil.get("no-iouring").toBoolean()) {
if (IOUring.isAvailable()) {
LOGGER.info { "Using IOUring transport" }
return IOUringTransport(threadsToUse)
} else {
LOGGER.info(IOUring.unavailabilityCause()) {
"IOUring transport not available"
}
}
}
if (Epoll.isAvailable()) {
LOGGER.info { "Using Epoll transport" }
return EpollTransport(threadsToUse)
} else {
LOGGER.info(Epoll.unavailabilityCause()) {
"Epoll transport not available"
if (!SystemPropertyUtil.get("no-epoll").toBoolean()) {
if (Epoll.isAvailable()) {
LOGGER.info { "Using Epoll transport" }
return EpollTransport(threadsToUse)
} else {
LOGGER.info(Epoll.unavailabilityCause()) {
"Epoll transport not available"
}
}
}
}
@ -144,9 +148,7 @@ class Netty(
override fun toServer(httpHandler: HttpHandler): Http4kServer = object : Http4kServer {
private val transport = NettyTransport.bestForPlatform(serverSettings.threads)
private lateinit var closeFuture: ChannelFuture
private lateinit var address: InetSocketAddress
private lateinit var channel: Channel
private val burstLimiter = object : GlobalTrafficShapingHandler(
transport.workerGroup, serverSettings.maxKilobitsPerSecond * 1000L / 8L, 0, 100
) {
@ -209,14 +211,12 @@ class Netty(
.option(ChannelOption.SO_BACKLOG, 1000)
.childOption(ChannelOption.SO_KEEPALIVE, true)
val channel = bootstrap.bind(InetSocketAddress(serverSettings.hostname, serverSettings.port)).sync().channel()
address = channel.localAddress() as InetSocketAddress
closeFuture = channel.closeFuture()
channel = bootstrap.bind(InetSocketAddress(serverSettings.hostname, serverSettings.port)).sync().channel()
}
override fun stop() = apply {
closeFuture.cancel(false)
transport.shutdownGracefully()
channel.closeFuture().sync()
}
override fun port(): Int = serverSettings.port