Skip to content

Commit 68cd70d

Browse files
committed
Move conditional shutdown hook to a service
1 parent b167c68 commit 68cd70d

File tree

2 files changed

+53
-23
lines changed

2 files changed

+53
-23
lines changed

src/main/kotlin/io/github/freya022/botcommands/internal/core/BContextImpl.kt

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import io.github.freya022.botcommands.api.core.utils.awaitShutdown
2020
import io.github.freya022.botcommands.api.core.utils.loggerOf
2121
import io.github.freya022.botcommands.internal.commands.application.ApplicationCommandsContextImpl
2222
import io.github.freya022.botcommands.internal.commands.text.TextCommandsContextImpl
23-
import io.github.freya022.botcommands.internal.core.service.SpringServiceContainer
2423
import io.github.freya022.botcommands.internal.utils.takeIfFinite
2524
import io.github.freya022.botcommands.internal.utils.unwrap
2625
import io.github.oshai.kotlinlogging.KotlinLogging
@@ -70,16 +69,6 @@ internal class BContextImpl internal constructor(
7069

7170
private val statusLock: ReentrantLock = ReentrantLock()
7271
private val statusCondition: Condition = statusLock.newCondition()
73-
private val shutdownHook: Thread? = when {
74-
// Spring has its own shutdown hook that will fire a shutdown event, we handle that
75-
serviceContainer is SpringServiceContainer -> null
76-
config.enableShutdownHook -> Thread(::shutdownNow)
77-
else -> null
78-
}
79-
80-
init {
81-
shutdownHook?.let { Runtime.getRuntime().addShutdownHook(it) }
82-
}
8372

8473
override fun dispatchException(message: String, t: Throwable?, extraContext: Map<String, Any?>) {
8574
if (config.disableExceptionsInDMs) return //Don't send DM exceptions in dev mode
@@ -166,8 +155,8 @@ internal class BContextImpl internal constructor(
166155

167156
override fun shutdown() {
168157
if (status == Status.SHUTTING_DOWN || status == Status.SHUTDOWN) return
169-
removeShutdownHook()
170158

159+
// Shutdown hook will be removed by [[DefaultShutdownHook]] if we use the built-in DI
171160
runBlocking { setStatus(Status.SHUTTING_DOWN) }
172161

173162
scheduleShutdownSignal(afterShutdownSignal = {
@@ -181,8 +170,8 @@ internal class BContextImpl internal constructor(
181170
override fun shutdownNow() {
182171
// Do not call shutdown(), more precisely do not call scheduleShutdownSignal() twice
183172
if (status == Status.SHUTTING_DOWN || status == Status.SHUTDOWN) return
184-
removeShutdownHook()
185173

174+
// Shutdown hook will be removed by [[DefaultShutdownHook]] if we use the built-in DI
186175
runBlocking { setStatus(Status.SHUTTING_DOWN) }
187176

188177
scheduleShutdownSignal(afterShutdownSignal = {
@@ -272,16 +261,6 @@ internal class BContextImpl internal constructor(
272261
return true
273262
}
274263

275-
private fun removeShutdownHook() {
276-
if (shutdownHook == null) return
277-
278-
try {
279-
Runtime.getRuntime().removeShutdownHook(shutdownHook)
280-
} catch (_: IllegalStateException) {
281-
282-
}
283-
}
284-
285264
private fun shutdownJDA(now: Boolean) {
286265
val jda = jdaOrNull ?: return logger.debug { "Ignoring JDA shutdown as there is no JDA instance registered" }
287266

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package io.github.freya022.botcommands.internal.core.service
2+
3+
import io.github.freya022.botcommands.api.core.BContext
4+
import io.github.freya022.botcommands.api.core.annotations.BEventListener
5+
import io.github.freya022.botcommands.api.core.config.BConfig
6+
import io.github.freya022.botcommands.api.core.events.BStatusChangeEvent
7+
import io.github.freya022.botcommands.api.core.events.PostLoadEvent
8+
import io.github.freya022.botcommands.api.core.service.ConditionalServiceChecker
9+
import io.github.freya022.botcommands.api.core.service.ServiceContainer
10+
import io.github.freya022.botcommands.api.core.service.annotations.BService
11+
import io.github.freya022.botcommands.api.core.service.annotations.ConditionalService
12+
import io.github.freya022.botcommands.api.core.service.annotations.Lazy
13+
import io.github.freya022.botcommands.api.core.service.annotations.RequiresDefaultInjection
14+
import io.github.freya022.botcommands.api.core.service.getService
15+
16+
@Lazy
17+
@BService
18+
@ConditionalService(DefaultShutdownHook.ActivationCondition::class)
19+
@RequiresDefaultInjection
20+
internal class DefaultShutdownHook internal constructor(
21+
context: BContext,
22+
) {
23+
24+
private val hook = Thread { context.shutdownNow() }
25+
26+
@BEventListener
27+
internal fun registerShutdownHook(event: PostLoadEvent) {
28+
Runtime.getRuntime().addShutdownHook(hook)
29+
}
30+
31+
@BEventListener
32+
internal fun onShuttingDown(event: BStatusChangeEvent) {
33+
if (event.newStatus == BContext.Status.SHUTTING_DOWN) {
34+
Runtime.getRuntime().removeShutdownHook(hook)
35+
}
36+
}
37+
38+
internal object ActivationCondition : ConditionalServiceChecker {
39+
40+
override fun checkServiceAvailability(
41+
serviceContainer: ServiceContainer,
42+
checkedClass: Class<*>
43+
): String? {
44+
if (!serviceContainer.getService<BConfig>().enableShutdownHook) {
45+
return "Default shutdown hook is disabled"
46+
}
47+
48+
return null
49+
}
50+
}
51+
}

0 commit comments

Comments
 (0)