Hello All! I seem to have an issue while working w...
# announcements
v
Hello All! I seem to have an issue while working with nested coroutines with single threaded dispatcher. When I call scope.launch() inside another scope.launch(), the inner block wont get executed if I use single threaded dispatcher. Here is an example
Copy code
val dispatcher = ScheduledThreadPoolExecutor(1).asCoroutineDispatcher()

val customScope = CoroutineScope(SupervisorJob() + dispatcher)

customScope.launch{
	//This block works fine.
	customScope.launch{
		//This block is not executing
	}
}
  However it woks fine If I change the dispatcher in the inner block. But In my case, I need to have the same dispatcher in both launches. Any help would be very much appreciated.
z
First of all, why do you need a dedicated thread for your dispatcher? The usual reasons people do this don’t actually need a dedicated thread and there are better ways.
Is there any other code in your coroutines? If you’re blocking somehow after you launch then the dispatcher will never be able to resume the inner coroutine.
v
Hi @Zach Klippenstein (he/him) [MOD] We are actually using V8 engine in our app. As you already know, working with V8 (JavaScript) requires single thread. So I need to have a single threaded dispatcher.
z
Ah, yea that sounds like a legit use case. Other question still stands though: are you doing anything else in that coroutine that could block the thread?
v
No. I don't see anything that could block the thread. When I put breakpoint in the flow, I can see the code executing till the inner launch line after that it Stops. It never goes to the inner block
b
It could be that your inner launch is a child of the scope, but not the outer launch. Maybe try using just
launch
for the inner one? (Instead of
customScope.launch
)
v
@bsharma Both are same right? I believe if we don’t put scope for launch inside another coroutine, it will inherit the scope from parent. Also in my use case, both launches need to have the same scope ( same single threaded dispatcher).
z
It’s very possible to modify the current context so they’re not the same. The code sample you gave looks fine, but presumably you left a lot of code out and so it would seem like some of the code you omitted might be the cause, so we’re basically just guessing at what that code might look like to figure out what’s going on. Can you post your actual code?
v
@Zach Klippenstein (he/him) [MOD] Thanks for the suggestion, I’ve analyzed the code from your point of view to find any blocking code and I think I found the clue The caller seems to be called the method in blocking manner which seems to be the problem although I don’t understand why. When I move “blockingAwait()” to “subscribe()” it works find (RxJava reference).   I’m not sure If I have the permission to post the actual code but here is the rough example.  
Copy code
val dispatcher = ScheduledThreadPoolExecutor(1).asCoroutineDispatcher()
val scope = CoroutineScope(SupervisorJob() + dispatcher)
fun cleanupStuff(){
	scope.launch{
	cleanupInternal().blockingAwait()
	//other stuff
	}
}
 
fun cleanupInternal(): Completable{
	return Completable{
	scope.launch{
			//This block is not executing if called with in blocking manner like .blockingAwait() but works when I call with .subscribe()
	}
	}	
}
  When I change the cleanupInternal().blockingAwait() to “cleanupInternal().subscribe()” it works. Why calling preference affects the implementation?
b
@Vijayakumar M There is a difference. You have to make sure that the parent job waits for all children. Guess which test exits early and doesn't print hello world.
z
yep that’s probably it. any call blocking the thread will prevent any other coroutines from being dispatched when you’re doing everything on a single thread
you’re calling
blockingAwait
from inside the
scope.launch
, which means you’re on the dedicated thread when the
blockingAwait
call blocks.
blockingAwait
will internally subscribe to your Completable, and trigger the
scope.launch
in
cleanupInternal
, but that coroutine can never launch because the thread that’s responsible for executing continuations (your dedicated thread) is blocked waiting for it to finish. Classic deadlock.
v
Ah.. I see where it went wrong. 🤦‍♂️. Thanks @Zach Klippenstein (he/him) [MOD] for your help. Much appreciated.
@bsimmons I got your point. In your case the parent coroutine (scope) finished before the child. Since both has the same scope, when the parent coroutine finishes, it also cancels the children. It is also a valid solution for these kind of issues. Thanks for your suggestion. Appreciated.