Как проверить внутри Ктора, что Netty действительно запущен? - PullRequest
1 голос
/ 03 мая 2019

Мне нужно выполнить некоторую инициализацию моего приложения Ktor, но я хочу сделать это только после того, как Netty будет готова принимать соединения.С другой стороны, я не хочу, чтобы такая инициализация происходила, если Netty не запускалась (например, с типичным «адресом, который уже используется»).

Я реализовал простой подход (см. Ниже),но мне интересно, возможно ли сделать это менее уродливым способом ?

Сначала я сохраняю ссылку на NettyApplicationEngine:

embeddedServer = embeddedServer(Netty, port, module)

Затем я использую channelsполе из NettyApplicationEngine для определения его состояния:

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)
            }
        }
    }

1 Ответ

1 голос
/ 13 мая 2019

Попробовав несколько разных подходов, я завершил самопроверку, которая просто отправляет HTTP-запрос моей собственной конечной точке, и, если HttpClient и обработчик маршрута выполнены успешно, я считаю, что Netty готов.

Сначала я регистрируюсьRouting.RoutingCallFinished событие с NettyApplicationEngine.environment.monitor (I dispose созданный обработчик позже).

Затем я повторяю все NettyApplicationEngine.environment.connectors и создаю Deferred s, которые будут выполнены из обработчика RoutingCallFinished.Кроме того, я запускаю асинхронные сопрограммы, которые будут проверять соответствующие конечные точки с помощью HttpClient.

После этого я awaitAll на этих Deferred с (и на Deferred также из обработчика событий ApplicationStarted).

...