Search code examples
kotlinkotlinx.coroutines

How to struture coroutine code without suspend function


I have a method called saveAccount

fun saveAccount(id: Int, newName: String): Account {
    val encryptedNames: List<String> = repository.findNamesById(id)
    val decryptedNames: List<String> = encryptedNames.map { cryptographyService.decrypt(it) }

    if(decryptedNames.contains(newName))
        throw IllegalStateException()

    return repository.save(newName)
}

I want to concurrently decrypt all names, so I did:

suspend fun saveAccount(id: Int, newName: String): Account {
    val encryptedNames: List<String> = repository.findNamesById(id)

    val decryptedNames: List<String> = encryptedNames.map { 
        CoroutineScope(Dispatchers.IO).async {
            cryptographyService.decrypt(it) 
        } 
    }.awaitAll()

    if(decryptedNames.contains(newName))
        throw IllegalStateException()

    return repository.save(newName)
}

Until now everything is fine, but the question is: I can't make saveAccount a suspend function. What should I do?


Solution

  • So, you want to decrypt each name in a separate coroutine, but saveAccount should only return when all decryption is done.

    You can use runBlocking for that:

    fun saveAccount(id: Int, newName: String): Account {
        // ...
        val decryptedNames = runBlocking {
            encryptedNames.map {
                CoroutineScope(Dispatchers.IO).async {
                    cryptographyService.decrypt(it) 
                }
            }.awaitAll()
        }
        // ...
    }
    

    This way saveAccount does not have to be a suspend function.