我需要对Ktor应用进行一些初始化,但是我只想在Netty准备好接受连接之后再进行。另一方面,如果Netty无法启动(例如,典型的“地址已在使用中”),我不希望发生这种初始化。
我实现了直接的方法(见下文),但我想知道是否有可能使它成为不太丑的方法?
首先,我保存对NettyApplicationEngine的引用:
embeddedServer = embeddedServer(Netty, port, module)
然后我使用NettyApplicationEngine中的channels
字段来确定其状态:
private fun NettyApplicationEngine.channelsReady(): Boolean {
val channelsField = this::class.members.find { it.name == "channels" }!!
channelsField.isAccessible = true
val channels = channelsField.call(this) as List<Channel>?
return !channels.isNullOrEmpty() && channels.all { it.isActive }
}
最后,我捕获到ApplicationStarted事件并旋转直到通道准备就绪:
environment.monitor.subscribe(ApplicationStarted) {
thread(start = true, name = "real netty postinit") {
for (i in 1..100) {
TimeUnit.MILLISECONDS.sleep(100)
if (embeddedServer.channelsReady()) break
}
if (embeddedServer.channelsReady()) {
// Initialization here
} else {
// Server didn't start
embeddedServer.stop(1, 1, TimeUnit.SECONDS)
}
}
}
答案 0 :(得分:1)
尝试了几种不同的方法后,我得出了一个自测结论,该测验仅将HTTP请求发送到自己的端点,并且如果HttpClient和路由处理程序都成功执行,则我认为Netty已经准备就绪。
首先,我向Routing.RoutingCallFinished
注册NettyApplicationEngine.environment.monitor
事件(稍后我dispose
创建一个处理程序)。
然后,我迭代所有NettyApplicationEngine.environment.connectors
并创建将由Deferred
处理程序完成的RoutingCallFinished
。此外,我启动了异步协程,这些协程将使用HttpClient检查相应的端点。
此后,我awaitAll
在那些Deferred
上(以及Deferred
事件处理程序的ApplicationStarted
上)。