gpt4 book ai didi

spring-boot - 协程解决之前的响应,kotlin

转载 作者:行者123 更新时间:2023-12-05 01:28:58 26 4
gpt4 key购买 nike

你好堆栈溢出!我正在编写一个小的服务网络应用程序,它接受使用 spring boot kotlin 发送电子邮件的数据。我的问题是如何让 Controller 在收到请求后立即响应并在后台线程中发送实际电子邮件。首先 Controller 发送邮件,然后在 rabbitMQ 上发布消息,然后才返回响应作为指定的字符串。

@RestController
class MailController(private val emailService: EmailService, private val msgSender: CustomMessageSender) {

@PostMapping("/api/sendemail")
suspend fun sendEmail(@RequestBody request: Email): String {
coroutineScope {
launch(Dispatchers.IO) {
try {
emailService.sendMail(request.to, request.subject!!, request.msg)
delay(2000)
msgSender.sendMessage()
} catch (e: Exception) {
println(e)
}
}
}
return "email queued"
}

最佳答案

对于这种需求,你需要了解CoroutineScope。作用域限制协程的生命周期。

当您使用 coroutineScope { ... } 时,您定义了一个将在 block 末尾结束的范围。意思是,在此函数可以恢复之前,在其中启动的所有子协程必须已经完成或已取消。换句话说,coroutineScope 将挂起当前协程,直到所有子协程都完成,这不是您想要的,因为在电子邮件发送之前您不会返回。

Side note: this is actually why coroutineScope is suspending. It's actually the suspending equivalent of runBlocking, which on the other hand blocks the current thread while waiting for child coroutines.

您需要的是一个比您的函数体更大的作用域。一种肮脏的方法是使用 GlobalScope(它与您的应用程序具有相同的生命周期)。一个更好的方法是定义一个与 Spring 组件的生命周期相关联的协程范围,这样如果您的组件被销毁,由它启动的协程就会被取消。

执行上述操作的一种方法是像这样定义一个范围:

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import javax.annotation.PreDestroy

@RestController
class MailController(
private val emailService: EmailService,
private val msgSender: CustomMessageSender
) {
// use a regular Job() if you want all coroutines to be cancelled if one fails
private val coroutineScope = CoroutineScope(SupervisorJob())

// this method is NOT suspending anymore, because it doesn't call
// suspending functions directly, it just starts a coroutine.
@PostMapping("/api/sendemail")
fun sendEmail(@RequestBody request: Email): String {
coroutineScope.launch(Dispatchers.IO) {
try {
emailService.sendMail(request.to, request.subject!!, request.msg)
delay(2000)
msgSender.sendMessage()
} catch (e: Exception) {
println(e)
}
}
return "email queued"
}


@PreDestroy
fun cancelScope() {
coroutineScope.cancel()
}
}

如果您的组件将始终与您的应用程序一样长寿,您还可以在应用程序级别定义您的自定义范围,并将其注入(inject)此处。 GlobalScope 在这种情况下仍然不是一个好主意,因为它会阻止您集中更改“全局”协程的协程上下文元素。例如,拥有应用程序范围允许您添加异常处理程序、更改线程池或提供协程名称。

关于spring-boot - 协程解决之前的响应,kotlin,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68127164/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com