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:
parent
e246924b57
commit
d1d7fcca7f
|
@ -23,7 +23,7 @@
|
||||||
# The size in mebibytes of the cache
|
# The size in mebibytes of the cache
|
||||||
# You can use megabytes instead in a pinch,
|
# You can use megabytes instead in a pinch,
|
||||||
# but just know the two are **NOT** the same.
|
# 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
|
# Optional settings for fancy geoip analytics
|
||||||
metrics_settings:
|
metrics_settings:
|
||||||
|
|
|
@ -32,7 +32,11 @@ object Main {
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun main(args: Array<String>) {
|
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 {
|
fun dieWithError(e: Throwable): Nothing {
|
||||||
|
|
|
@ -175,8 +175,14 @@ class MangaDexClient(private val settingsFile: File, databaseFile: File, cacheFo
|
||||||
|
|
||||||
storage.maxSize = (newSettings.maxCacheSizeInMebibytes * 1024 * 1024 * 0.95).toLong()
|
storage.maxSize = (newSettings.maxCacheSizeInMebibytes * 1024 * 1024 * 0.95).toLong()
|
||||||
|
|
||||||
stopImageServer()
|
if (imageServer != null) {
|
||||||
startImageServer()
|
stopImageServer()
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
startImageServer()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
LOGGER.warn(e) { "Error starting the image server" }
|
||||||
|
}
|
||||||
} catch (e: UnrecognizedPropertyException) {
|
} catch (e: UnrecognizedPropertyException) {
|
||||||
LOGGER.warn { "Settings file is invalid: '$e.propertyName' is not a valid setting" }
|
LOGGER.warn { "Settings file is invalid: '$e.propertyName' is not a valid setting" }
|
||||||
} catch (e: JsonProcessingException) {
|
} catch (e: JsonProcessingException) {
|
||||||
|
@ -189,8 +195,8 @@ class MangaDexClient(private val settingsFile: File, databaseFile: File, cacheFo
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun validateSettings(settings: ClientSettings) {
|
private fun validateSettings(settings: ClientSettings) {
|
||||||
if (settings.maxCacheSizeInMebibytes < 1024) {
|
if (settings.maxCacheSizeInMebibytes < 20480) {
|
||||||
throw ClientSettingsException("Config Error: Invalid max cache size, must be >= 1024 MiB (1GiB)")
|
throw ClientSettingsException("Config Error: Invalid max cache size, must be >= 20480 MiB (20 GiB)")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isSecretValid(clientSecret: String): Boolean {
|
fun isSecretValid(clientSecret: String): Boolean {
|
||||||
|
|
|
@ -58,7 +58,7 @@ object Shutdown : State()
|
||||||
data class GracefulStop(
|
data class GracefulStop(
|
||||||
val lastRunning: Running,
|
val lastRunning: Running,
|
||||||
val counts: Int = 0,
|
val counts: Int = 0,
|
||||||
val nextState: State = Uninitialized,
|
val nextState: State,
|
||||||
val action: () -> Unit = {}
|
val action: () -> Unit = {}
|
||||||
) : State()
|
) : State()
|
||||||
|
|
||||||
|
@ -193,7 +193,7 @@ class ServerManager(
|
||||||
if (settings.serverSettings.maxMebibytesPerHour != 0L && settings.serverSettings.maxMebibytesPerHour * 1024 * 1024 /* MiB to bytes */ < currentBytesSent) {
|
if (settings.serverSettings.maxMebibytesPerHour != 0L && settings.serverSettings.maxMebibytesPerHour * 1024 * 1024 /* MiB to bytes */ < currentBytesSent) {
|
||||||
LOGGER.info { "Stopping image server as hourly bandwidth limit reached" }
|
LOGGER.info { "Stopping image server as hourly bandwidth limit reached" }
|
||||||
|
|
||||||
this.state = GracefulStop(lastRunning = state)
|
this.state = GracefulStop(lastRunning = state, nextState = Uninitialized)
|
||||||
} else {
|
} else {
|
||||||
pingControl()
|
pingControl()
|
||||||
}
|
}
|
||||||
|
@ -245,7 +245,7 @@ class ServerManager(
|
||||||
if (!state.settings.logicalEqual(newSettings)) {
|
if (!state.settings.logicalEqual(newSettings)) {
|
||||||
LOGGER.info { "Doing internal restart of HTTP server to refresh settings" }
|
LOGGER.info { "Doing internal restart of HTTP server to refresh settings" }
|
||||||
|
|
||||||
this.state = GracefulStop(lastRunning = state) {
|
this.state = GracefulStop(lastRunning = state, nextState = Uninitialized) {
|
||||||
loginAndStartServer()
|
loginAndStartServer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,9 +77,9 @@ sealed class NettyTransport(threads: Int) {
|
||||||
)
|
)
|
||||||
|
|
||||||
fun shutdownGracefully() {
|
fun shutdownGracefully() {
|
||||||
bossGroup.shutdownGracefully()
|
bossGroup.shutdownGracefully().sync()
|
||||||
workerGroup.shutdownGracefully()
|
workerGroup.shutdownGracefully().sync()
|
||||||
executor.shutdownGracefully()
|
executor.shutdownGracefully().sync()
|
||||||
}
|
}
|
||||||
|
|
||||||
private class NioTransport(threads: Int) : NettyTransport(threads) {
|
private class NioTransport(threads: Int) : NettyTransport(threads) {
|
||||||
|
@ -111,21 +111,25 @@ sealed class NettyTransport(threads: Int) {
|
||||||
LOGGER.info { "Choosing a transport using $threadsToUse threads" }
|
LOGGER.info { "Choosing a transport using $threadsToUse threads" }
|
||||||
|
|
||||||
if (name.startsWith("linux")) {
|
if (name.startsWith("linux")) {
|
||||||
if (IOUring.isAvailable()) {
|
if (!SystemPropertyUtil.get("no-iouring").toBoolean()) {
|
||||||
LOGGER.info { "Using IOUring transport" }
|
if (IOUring.isAvailable()) {
|
||||||
return IOUringTransport(threadsToUse)
|
LOGGER.info { "Using IOUring transport" }
|
||||||
} else {
|
return IOUringTransport(threadsToUse)
|
||||||
LOGGER.info(IOUring.unavailabilityCause()) {
|
} else {
|
||||||
"IOUring transport not available"
|
LOGGER.info(IOUring.unavailabilityCause()) {
|
||||||
|
"IOUring transport not available"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Epoll.isAvailable()) {
|
if (!SystemPropertyUtil.get("no-epoll").toBoolean()) {
|
||||||
LOGGER.info { "Using Epoll transport" }
|
if (Epoll.isAvailable()) {
|
||||||
return EpollTransport(threadsToUse)
|
LOGGER.info { "Using Epoll transport" }
|
||||||
} else {
|
return EpollTransport(threadsToUse)
|
||||||
LOGGER.info(Epoll.unavailabilityCause()) {
|
} else {
|
||||||
"Epoll transport not available"
|
LOGGER.info(Epoll.unavailabilityCause()) {
|
||||||
|
"Epoll transport not available"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -144,9 +148,7 @@ class Netty(
|
||||||
override fun toServer(httpHandler: HttpHandler): Http4kServer = object : Http4kServer {
|
override fun toServer(httpHandler: HttpHandler): Http4kServer = object : Http4kServer {
|
||||||
private val transport = NettyTransport.bestForPlatform(serverSettings.threads)
|
private val transport = NettyTransport.bestForPlatform(serverSettings.threads)
|
||||||
|
|
||||||
private lateinit var closeFuture: ChannelFuture
|
private lateinit var channel: Channel
|
||||||
private lateinit var address: InetSocketAddress
|
|
||||||
|
|
||||||
private val burstLimiter = object : GlobalTrafficShapingHandler(
|
private val burstLimiter = object : GlobalTrafficShapingHandler(
|
||||||
transport.workerGroup, serverSettings.maxKilobitsPerSecond * 1000L / 8L, 0, 100
|
transport.workerGroup, serverSettings.maxKilobitsPerSecond * 1000L / 8L, 0, 100
|
||||||
) {
|
) {
|
||||||
|
@ -209,14 +211,12 @@ class Netty(
|
||||||
.option(ChannelOption.SO_BACKLOG, 1000)
|
.option(ChannelOption.SO_BACKLOG, 1000)
|
||||||
.childOption(ChannelOption.SO_KEEPALIVE, true)
|
.childOption(ChannelOption.SO_KEEPALIVE, true)
|
||||||
|
|
||||||
val channel = bootstrap.bind(InetSocketAddress(serverSettings.hostname, serverSettings.port)).sync().channel()
|
channel = bootstrap.bind(InetSocketAddress(serverSettings.hostname, serverSettings.port)).sync().channel()
|
||||||
address = channel.localAddress() as InetSocketAddress
|
|
||||||
closeFuture = channel.closeFuture()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun stop() = apply {
|
override fun stop() = apply {
|
||||||
closeFuture.cancel(false)
|
|
||||||
transport.shutdownGracefully()
|
transport.shutdownGracefully()
|
||||||
|
channel.closeFuture().sync()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun port(): Int = serverSettings.port
|
override fun port(): Int = serverSettings.port
|
||||||
|
|
Loading…
Reference in a new issue