My Kotlin App is using Spring to expose an API that should execute a long task in the background. We need to return
@PutMapping("/refresh")
fun refresh() = {
GlobalScope.launch(IO) { refreshDataFromCache() }
return ResponseEntity.accepted().body("""{"result": "accepted"}""")
}
IntelliJ complains that using the GlobalScope is an anti-pattern. However, I cannot just add suspend to the controller function or it won't work. Neither I can use runBlocking or the method will need to wait until finishing producing a REST timeout
What should I add as the scope of this function to use structured concurrency?
CodePudding user response:
To leverage structured concurrency, as described here in the Parallel decomposition section, you can use coroutineScope
function:
@PutMapping("/refresh")
suspend fun refresh() = coroutineScope {
async { refreshDataFromCache() } // this will run in parallel
ResponseEntity.accepted().body("""{"result": "accepted"}""")
}
refresh()
should be marked as suspend
to use coroutineScope
.
CodePudding user response:
You probably want to inject some scope other than GlobalScope into your resource. If your framework already provides some sort of "application scope" that will be cancelled when your application shuts down, that seems appropriate.
Failing that -- a coroutine scope is just a wrapper around a Job (well, and other coroutine context items). So you can create a new Job during app startup, and simply CoroutineScope(job)
to make your application coroutine scope. Then just do job.cancel()
during app shutdown and that will ensure any coroutines launched in that scope will be cancelled.