You might get more interest in this question if you could distil the code down to a minimal, reproducible example. (Ideally, it’d then be small enough to post the code here directly.)
It might also help to post the exception message (and its stack trace) here too.
Here is the building class, this is the class which I have a problem with.
package building
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlin.random.Random
class BuildingConstructionFailed: Exception("Building Construction Failed")
class Building ( val name: String, var floors: Int = 0, private val scope: CoroutineScope) {
suspend fun makeFoundation() = scope.launch {
delay(300)
speakThroughBullhorn("[${java.lang.Thread.currentThread().name}] The foundation is ready")
}
suspend fun buildFloor(floor: Int) = scope.launch{
if (Random.nextBoolean()) {
delay(100)
speakThroughBullhorn("[${java.lang.Thread.currentThread().name}] The $floor'th is raised")
++floors
} else {
throw BuildingConstructionFailed()
}
}
suspend fun placeWindows(floor: Int) = scope.launch{
delay(100)
speakThroughBullhorn("[${java.lang.Thread.currentThread().name}] Windows are placed on the $floor'th")
}
suspend fun installDoors(floor: Int) = scope.launch{
delay(100)
speakThroughBullhorn("[${java.lang.Thread.currentThread().name}] Doors are installed on the $floor'thfloor")
}
suspend fun provideElectricity(floor: Int) = scope.launch{
delay(100)
speakThroughBullhorn("[${java.lang.Thread.currentThread().name}] Electricity is provided on the $floor'th floor")
}
suspend fun buildRoof() = scope.launch{
delay(200)
speakThroughBullhorn("[${java.lang.Thread.currentThread().name}] The roof is ready")
}
suspend fun fitOut(floor: Int) = scope.launch{
delay(200)
speakThroughBullhorn("[${java.lang.Thread.currentThread().name}] The $floor'th is furnished")
}
fun speakThroughBullhorn(message: String) = println(message)
}
This the Building Yard class.
package buildingyardpack
import building.*
import kotlinx.coroutines.*
class BuildingYard {
suspend fun startProjects(buildingsToMake: List<Pair<String, Int>>) {
var tasks = mutableListOf<Deferred<Unit>>()
runBlocking {
buildingsToMake.forEach { tasks.add(async(Dispatchers.IO) {startProject(it.first, it.second)})}
}
tasks.awaitAll()
}
suspend fun startProject(name: String, floors: Int) {
val building = withContext(Dispatchers.Default) {
val building = Building(name, scope=this)
val cores = Runtime.getRuntime().availableProcessors()
building.speakThroughBullhorn("The building of $name is started with $cores building machines engaged")
// Any of these phases until foundation isn't ready
building.makeFoundation().join()
(1..floors).forEach {
// A floor should be raised before we can decorate it
try {
building.buildFloor(it).join()
} catch (exception: BuildingConstructionFailed) {
building.buildFloor(it).join()
}
// These decorations could be made at the same time
building.placeWindows(it)
building.installDoors(it)
building.provideElectricity(it)
building.fitOut(it)
}
building.buildRoof().join()
building
}
if (building.floors == floors ) {
building.speakThroughBullhorn("${building.name} is ready!")
}
}
}
The line I’m having problem with is the one which generates the building exception. Not only does it not properly generate the exception but also it is not caught correctly,
How should it be generated? (Looks like it’s doing just what you told it to. It would be normal for the exception to hold some information about the reason for the failure, or at least a custom message, but it’s not compulsory.)
I assume this is for learning/testing purposes? (It would NOT be normal to throw an exception at random like that!)
How should it be caught? (Looks like you’re doing nothing to catch it, so logging the error and stopping the thread, as it did, is the normal behaviour.)
If I understand what’s going on the issue is here:
Nothing is catching the exception which could be thrown inside that catch block. If your intetion is to keep try calling building.buildFloor(it).join() until it doesn’t throw, you’ll need a loop around it.