Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/git/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何确保ktor websocket客户端创建的所有Kotlin协同路由都已清除?_Kotlin_Kotlin Coroutines_Ktor - Fatal编程技术网

如何确保ktor websocket客户端创建的所有Kotlin协同路由都已清除?

如何确保ktor websocket客户端创建的所有Kotlin协同路由都已清除?,kotlin,kotlin-coroutines,ktor,Kotlin,Kotlin Coroutines,Ktor,我正试着去思考Kotlin协同程序和Ktors websocket支持。我的理解是,runBlocking将创建一个作用域,并且只要该作用域(或子作用域)中存在协同路由,它就会阻塞,但是我在下面的测试中调用runBlocking返回时,仍然有两个协同路由处于活动状态 我为什么在这里泄露协同程序 package dummy import io.ktor.client.HttpClient import io.ktor.client.features.websocket.WebSockets im

我正试着去思考Kotlin协同程序和Ktors websocket支持。我的理解是,
runBlocking
将创建一个作用域,并且只要该作用域(或子作用域)中存在协同路由,它就会阻塞,但是我在下面的测试中调用
runBlocking
返回时,仍然有两个协同路由处于活动状态

我为什么在这里泄露协同程序

package dummy

import io.ktor.client.HttpClient
import io.ktor.client.features.websocket.WebSockets
import io.ktor.client.features.websocket.wss
import io.ktor.http.HttpMethod
import io.ktor.http.cio.websocket.Frame
import io.ktor.http.cio.websocket.readBytes
import io.ktor.http.cio.websocket.readText
import io.ktor.util.KtorExperimentalAPI
import kotlinx.coroutines.*
import kotlinx.coroutines.debug.DebugProbes
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test

@ExperimentalCoroutinesApi
@KtorExperimentalAPI
class WebsocketTest {

    @Test
    fun tidy() {
        DebugProbes.install()

        runBlocking {
            val socketJob = Job()

            launch(CoroutineName("Websocket") + socketJob) {
                println("Connecting to websocket")
                connectWebsocket(socketJob)
                println("Websocket dead?")
            }

            launch(CoroutineName("Ninja socket killer")) {
                delay(3500)
                println("Killing websocket client")
                socketJob.cancel(message = "Time to die..")
            }
        }

        println("\n\n-------")
        DebugProbes.dumpCoroutines(System.err)
        Assertions.assertEquals(0, DebugProbes.dumpCoroutinesInfo().size, "It would be nice if all coroutines had been cleared up by now..")
    }

}


@KtorExperimentalAPI
private suspend fun connectWebsocket(socketJob: CompletableJob) {

    val client = HttpClient {
        install(WebSockets)
    }

    socketJob.invokeOnCompletion {
        println("Shutting down ktor http client")
        client.close()
    }

    client.wss(
            method = HttpMethod.Get,
            host = "echo.websocket.org",
            port = 443,
            path = "/"
    ) {

        send(Frame.Text("Hello World"))

        for (frame in incoming) {
            when (frame) {
                is Frame.Text -> println(frame.readText())
                is Frame.Binary -> println(frame.readBytes())
            }

            delay(1000)
            send(Frame.Text("Hello World"))
        }
    }

}
build.gradle.kts

import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.gradle.api.tasks.testing.logging.TestLogEvent

plugins {
    kotlin("jvm") version "1.3.41" apply true
}

repositories {
    mavenCentral()
}

val ktorVersion = "1.2.3"
val junitVersion = "5.5.1"

dependencies {
    implementation(kotlin("stdlib-jdk8"))

    implementation("io.ktor:ktor-client-websockets:$ktorVersion")
    implementation("io.ktor:ktor-client-okhttp:$ktorVersion")

    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-debug:1.3.0-RC2")


    testImplementation("org.junit.jupiter:junit-jupiter-api:$junitVersion")
    testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:$junitVersion")
}

tasks.withType<Test> {
    useJUnitPlatform()
    testLogging {
        showExceptions = true
        showStackTraces = true
        exceptionFormat = TestExceptionFormat.FULL
        events = setOf(TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.FAILED)
    }
}
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
导入org.gradle.api.tasks.testing.logging.TestLogEvent
插件{
kotlin(“jvm”)版本“1.3.41”适用
}
存储库{
mavenCentral()
}
val ktorVersion=“1.2.3”
val junitVersion=“5.5.1”
依赖关系{
实施(kotlin(“stdlib-jdk8”))
实现(“io.ktor:ktor客户端WebSocket:$ktorVersion”)
实现(“io.ktor:ktor客户端okhttp:$ktorVersion”)
实现(“org.jetbrains.kotlinx:kotlinx协程调试:1.3.0-RC2”)
测试实现(“org.junit.jupiter:junit-jupiter-api:$junitVersion”)
testRuntimeOnly(“org.junit.jupiter:junit-jupiter引擎:$junitVersion”)
}
tasks.withType{
useJUnitPlatform()
测试记录{
showExceptions=true
showStackTraces=true
exceptionFormat=TestExceptionFormat.FULL
events=setOf(TestLogEvent.PASSED、TestLogEvent.SKIPPED、TestLogEvent.FAILED)
}
}

看来我已经明白了(显然是在我把头发扯下来,开始写这篇文章之后)。当我写这篇文章时,我泄露了两个协同程序,其中一个“自行解决”(我对此不太高兴,但无论我做什么,我都无法复制它)

第二个协同路由泄漏,因为Ktor中的Nonce.kt在GlobalScope中显式启动协同路由

刚刚发现了这个宝石:似乎有一个“泄露”的协同程序被明确地发布到了全局范围。
private val nonceGeneratorJob =
GlobalScope.launch(
    context = Dispatchers.IO + NonCancellable + NonceGeneratorCoroutineName,
    start = CoroutineStart.LAZY
) { ....