如何在 Controller 方法中创建协程以调用挂起函数

how create a coroutine inside a Controller method in order to call a suspend function

目标:我的微服务必须使用另一个 Rest 端点,我正在尝试遵循 Coroutines (Async)

这是我在服务中编码以使用另一个休息端点的方式

服务

suspend fun getCoroutine(){

    val someData = getData()

    print(someData)
}

suspend fun getData(): String {

    
    val client = HttpClient.newBuilder()
            .version(HttpClient.Version.HTTP_2)
            .authenticator(Authenticator.getDefault())
            .build();

    val request = HttpRequest.newBuilder()
            .uri(URI.create("http://localhost:3000/employees"))
            .build();

    val response = client.sendAsync(request, BodyHandlers.ofString());
    return response.get().body() // suspend and return String not a Future
}

我想从我的控制器调用“suspend fun getCoroutine()”方法

package com.tolearn.endpoint

import com.tolearn.DemoGrpcKafkaReply
import com.tolearn.DemoGrpcKafkaRequest
import com.tolearn.DemoGrpcKafkaServiceGrpc
import com.tolearn.service.DemoService
import io.grpc.stub.StreamObserver
import java.util.*
import javax.inject.Inject
import javax.inject.Singleton


@Singleton
class DemoEndpoint : DemoGrpcKafkaServiceGrpc.DemoGrpcKafkaServiceImplBase(){

    @Inject
    lateinit var demoService: DemoService

    override fun send(request: DemoGrpcKafkaRequest?, responseObserver: StreamObserver<DemoGrpcKafkaReply>?) {

        demoService.getCoroutine()

    }
}

我是协程的新手。我了解到挂起函数只能从另一个挂起函数或协程中调用,所以在我的例子中,我想创建一个协程。谷歌搜索后我尝试了

override fun send(request: DemoGrpcKafkaRequest?, responseObserver: StreamObserver<DemoGrpcKafkaReply>?) {

    val tryingCoroutine = runBlocking { demoService.getCoroutine() }

但是无法解决runBlocking

我也试过基于docs reference也是lauch无法解决

override fun send(request: DemoGrpcKafkaRequest?, responseObserver: StreamObserver<DemoGrpcKafkaReply>?) {
    
    launch( demoService.getCoroutine() ) { // not confined -- will work with main thread

    }

这里是build.gradle

plugins {
    id("org.jetbrains.kotlin.jvm") version "1.4.10"
    id("org.jetbrains.kotlin.kapt") version "1.4.10"
    id("org.jetbrains.kotlin.plugin.allopen") version "1.4.10"
    id("com.github.johnrengelman.shadow") version "6.1.0"
    id("io.micronaut.application") version "1.2.0"
    id("com.google.protobuf") version "0.8.13"
}

version = "0.1"
group = "com.tolearn"

repositories {
    mavenLocal()
    jcenter()
    mavenCentral()

}

micronaut {
    testRuntime("junit5")
    processing {
        incremental(true)
        annotations("com.tolearn.*")
    }
}

dependencies {
    implementation("io.micronaut:micronaut-validation")
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:${kotlinVersion}")
    implementation("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}")
    implementation("io.micronaut.kotlin:micronaut-kotlin-runtime")
    implementation("io.micronaut:micronaut-runtime")
    implementation("io.micronaut.grpc:micronaut-grpc-runtime")
    implementation("javax.annotation:javax.annotation-api")
    implementation("io.micronaut.kafka:micronaut-kafka")

    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:'1.4.2")

    runtimeOnly("ch.qos.logback:logback-classic")
    runtimeOnly("com.fasterxml.jackson.module:jackson-module-kotlin")
    testImplementation("io.micronaut:micronaut-http-client")
}


application {
    mainClass.set("com.tolearn.ApplicationKt")
}

java {
    sourceCompatibility = JavaVersion.toVersion("11")
}

tasks {
    compileKotlin {
        kotlinOptions {
            jvmTarget = "11"
        }
    }
    compileTestKotlin {
        kotlinOptions {
            jvmTarget = "11"
        }
    }


}

sourceSets {
    main {
        java {
            srcDirs("build/generated/source/proto/main/grpc")
            //srcDirs 'build/generated/source/proto/main/grpckt'
            srcDirs("build/generated/source/proto/main/java")
        }
    }
}

protobuf {
    protoc { artifact = "com.google.protobuf:protoc:3.14.0" }
    plugins {
        grpc { artifact = "io.grpc:protoc-gen-grpc-java:1.33.1" }
        //grpckt { artifact = "io.grpc:protoc-gen-grpc-kotlin:1.0.0" }
    }
    generateProtoTasks {
        all()*.plugins {
            grpc {}
            //grpckt {}
        }
    }
}

主要问题:我需要做什么才能从我的控制器方法中调用挂起函数?第二个问题,我是否在尝试从 Controller 方法调用挂起函数?在这种情况下,我尝试利用协程是不是错了?

*** 编辑 1

val tryingCoroutine = runBlocking {
    coroutineScope { // Creates a coroutine scope
        launch {
            demoService.getCoroutine()
            println("Task from nested launch")
        }
    }
}
println(tryingCoroutine.isCompleted)

您需要添加 kotlinx-coroutines-core 依赖项来解析作用域 (runBlocking/launch)。

这里是 link 到 maven 仓库: https://mvnrepository.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core

范围文档:
https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html

将范围添加到项目后,您应该能够 运行 在非暂停 block.Also 中暂停功能,您可以使用 CoroutineExceptionHandler 来处理错误。 https://kotlinlang.org/docs/reference/coroutines/exception-handling.html#coroutineexceptionhandler

从技术上讲,控制器应该将任何长运行宁操作移交给另一个线程,并return适当的响应。所以你在做任何奇怪的事情。