Hello, I need some help to debug a situation. Any ...
# coroutines
g
Hello, I need some help to debug a situation. Any hint would be greatly appreciated! I have the following behavior:
Copy code
suspend fun sendMessage(total: Int) = coroutineScope {
  repeat(total) {
    launch {
      println("sending $it")
      internalSendToAsync(it).await() // internalSendToAsync is a function returning a CompletableFuture
      println("sent $it")
    }
  }
}
Then in my tests, everything works fine (I see 1000 "sending" and 1000 "sent") when I do:
Copy code
sendMessage(1000)
But if I do:
Copy code
CoroutineScope(<http://Dispatchers.IO|Dispatchers.IO>).launch {
  sendMessage(1000) 
}.join()
Then I can see 1000 "sending $it" but 0 "sent $it". I have 64 starts of the fun
internalSendToAsync
. I understand that I have all threads stuck in those calls, but I do not understand why, especially as it works for a simple call. Even more strange: everything works fine again if I do this:
Copy code
sendMessage(1000) 
CoroutineScope(<http://Dispatchers.IO|Dispatchers.IO>).launch {
  sendMessage(1000) 
}.join()
Any hint about what could be the issues?
d
If you replace
internalSendToAsync(it)
with
async { delay(100) }
, does the code behave like you expect? Maybe
internalSendToAsync
is not prepared to handle multithreading. When you write
sendMessage(1000)
in your tests, I assume you mean you use
runTest { }
? In that case, everything happens on just one thread.
g
internalSendToAsync
is not a suspendable function. It's a "normal" function asynchronously sending a message into a queue.
Actually I'm still digging but it seems that the actual arguments of
internalSendToAsync
may create some sort of locking when initialized
d
Ok, here's an alternative to rule out (or confirm) that this is the result of multithreading not being supported in `internalSendToAsync`:
Copy code
suspend fun sendMessage(total: Int) = coroutineScope {
  newSingleThreadContext("thread").use { ctx ->
    repeat(total) {
      launch {
        println("sending $it")
        withContext(ctx) {
          internalSendToAsync(it).await()
        }
        println("sent $it")
      }
    }
  }
}
This way, all
internalSendToAsync
invocations will be on just one thread.
👀 1
g
ok - sorry for the annoyance - it appears that the arguments of internalSendToAsync had a initialization method including a runBlocking method 😅. Thank you for your support.
🙂 1