Spring MVC 从控制器启动Kotlin中的任务时使用什么作用域?

nkhmeac6  于 2022-11-15  发布在  Spring
关注(0)|答案(2)|浏览(181)

我的Kotlin应用程序正在使用Spring公开一个API,该API应该在后台执行一个长任务。

  1. @PutMapping("/refresh")
  2. fun refresh() = {
  3. GlobalScope.launch(IO) { refreshDataFromCache() }
  4. return ResponseEntity.accepted().body("""{"result": "accepted"}""")
  5. }

IntelliJ抱怨说使用GlobalScope是一种反模式。但是,我不能只将 suspend 添加到控制器函数中,否则它将不起作用。我也不能使用 runBlocking,否则该方法将需要等待,直到完成生成REST超时
要使用structured concurrency,应该添加什么作为此函数的作用域?

jgzswidk

jgzswidk1#

您可能希望将GlobalScope以外的某个作用域注入到资源中。如果您的框架已经提供了某种“应用程序作用域”,当您的应用程序关闭时,该作用域将被取消,这似乎是合适的。
如果做不到这一点--协程作用域只是一个Job的 Package 器(当然,还有其他的协程上下文项)。所以你可以在应用启动时创建一个新的Job,然后简单地CoroutineScope(job)来使你的应用成为协程作用域。然后在应用关闭时执行job.cancel(),这将确保在该作用域中启动的任何协程都将被取消。
编辑添加我的解决方案:

  1. private val jobScope = CoroutineScope(IO)
  2. @PutMapping("/refresh")
  3. fun refresh() = {
  4. jobScope.launch(IO) { refreshDataFromCache() }
  5. return ResponseEntity.accepted().body("""{"result": "accepted"}""")
  6. }
  7. @PreDestroy
  8. fun stopTasks() {
  9. jobScope.cancel("Closing app")
  10. }
展开查看全部
ktecyv1j

ktecyv1j2#

要利用结构化并发,如here in the Parallel decomposition section所述,可以使用coroutineScope函数:

  1. @PutMapping("/refresh")
  2. suspend fun refresh() = coroutineScope {
  3. async { refreshDataFromCache() } // this will run in parallel
  4. ResponseEntity.accepted().body("""{"result": "accepted"}""")
  5. }

refresh()应该标记为suspend才能使用coroutineScope

相关问题