2
\$\begingroup\$

I have written this function to load data from the database, change it asynchronously and return the new data. It appears to work fine, but since I am new to Kotlin, I wanted to ask if this code is ok by industry standards.

override fun update(resourceCommand: UpdateResourceCommand): List<Resource> = runBlocking {
    val resources = resourceCommand.resources.map {
        async {
            val resource = load(it)
            resource.isProtected = it.isProtected
            resource
        }
    }.awaitAll()
    return@runBlocking resources
}

Don't know if this matters, but I am using Kotlin with Spring-Boot.

\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

The power of coroutines in Kotlin is that they should not block a thread when used correctly.

As soon as you use runBlocking, all that goes out the window. As stated in the documentation for runBlocking:

Runs a new coroutine and blocks the current thread interruptibly until its completion.


You haven't added the information about the load method but I do hope that's a suspend function. Otherwise using async will not have much meaning.


If we check awaitAll that method says: (emphasis mine)

Awaits for completion of given deferred values without blocking a thread and resumes normally with the list of values when all deferred computations are complete or resumes with the first thrown exception if any of computations complete exceptionally including cancellation.

So that's fine.


Because of the runBlocking invocation, this does not live up to industry standards regarding usage of Kotlin coroutines and, unfortunately, demonstrates a lack of understanding about coroutines. I'll be the first one to admit that I don't understand everything about coroutines (and god knows if I ever will) but this is not correct usage.

The best solution would be if you could make the whole update function a suspend fun and if it could launch its own coroutine using some existing CoroutineScope.

I would recommend reading through https://spring.io/guides/tutorials/spring-webflux-kotlin-rsocket/ (Disclaimer: Haven't read it fully myself as I use Ktor and not Spring Boot) and especially the part about suspending functions - except that I would recommend using fun thisIsATest() = runTest { ... } instead of runBlocking inside a test method.

I would also recommend experimenting and playing around a lot with coroutines to learn them better. And read lots and lots of the documentation for methods and classes. Try to understand (at least the basics of) CoroutineScope, CoroutineContext, CoroutineDispatcher (hint: You probably want to use Dispatchers.IO for your database connection) and how they interact.

\$\endgroup\$
2
  • \$\begingroup\$ Possible counterpoint: This function is overriding something, so they might be locked into legacy code or a library that can only accept blocking work in this function. The use of map/async/awaitAll means using runBlocking isn't a complete redundancy, because it is at least doing some tasks in parallel. \$\endgroup\$
    – Tenfour04
    Commented Aug 24, 2022 at 1:42
  • \$\begingroup\$ @Tenfour04 Just to be clear: The runBlocking will only run tasks in "parallell" if one coroutine is suspended. If the call that is made in load is a blocking call, then the whole thread will be blocked while waiting for a response. If the call is suspending properly, then yes, it will be able to run some tasks in parallell. But it will not be using multiple threads, everything will be just on one thread - but different coroutines. \$\endgroup\$ Commented Aug 24, 2022 at 22:43
1
\$\begingroup\$

Not commenting on meta functionality. To cleanup your code a bit, I suggest getting rid of your local variables (and return) like this:

override fun update(resourceCommand: UpdateResourceCommand): List<Resource> = runBlocking {
    resourceCommand.resources.map {
        async {
            load(it).apply {
                isProtected = it.isProtected
            }
        }
    }.awaitAll()
}
\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.