CoroutineScope
In simple terms, a CoroutineScope in Kotlin is like a "container" that manages your coroutines. It defines the boundaries and the "lifetime" for the coroutines you start within it, ensuring that they are automatically canceled when they are no longer needed.
From eg
Go to text ā
GT-Sandbox-Snapshot: Example - 1, Cancelling using SupervisorJob
Code
package com.glassthought.sandbox
import gt.sandbox.util.output.Out
import kotlinx.coroutines.*
interface Server {
suspend fun start()
suspend fun stop()
}
val out = Out.standard()
class ServerImpl(
private val scope: CoroutineScope // Injected scope for better control
) : Server {
private val job = SupervisorJob() // Ensures independent coroutines
private val serverScope = scope + job
override suspend fun start() {
out.info("Starting server")
serverScope.launch(CoroutineName("ServerWork-1")) {
out.info("Running server work in thread: ${Thread.currentThread().name}")
delay(2000)
out.info("ServerWork-1 completed")
}
serverScope.launch(CoroutineName("ServerWork-2")) {
out.info("Running additional server work in thread: ${Thread.currentThread().name}")
delay(1500)
out.info("ServerWork-2 completed")
}
}
override suspend fun stop() {
out.info("Stopping server")
job.cancel()
}
}
fun main() = runBlocking {
out.info("--------------------------------------------------------------------------------")
out.info("Example where the server is aborted prior to finishing:")
runWithDelayBeforeStopping(1000)
out.info("--------------------------------------------------------------------------------")
out.info("Example where the server has time to finish:")
runWithDelayBeforeStopping(3000)
}
private suspend fun runWithDelayBeforeStopping(delayBeforeStopping: Long) {
val server = ServerImpl(CoroutineScope(Dispatchers.Default)) // Inject external scope
server.start()
delay(delayBeforeStopping) // Use delay instead of Thread.sleep
server.stop()
}
Command to reproduce:
gt.sandbox.checkout.commit bed37c930bb1de4223cb \
&& cd "${GT_SANDBOX_REPO}" \
&& cmd.run.announce "./gradlew run --quiet"
Recorded output of command:
[elapsed: 51ms][š„/tname:main/tid:1][coroutine:unnamed] --------------------------------------------------------------------------------
[elapsed: 62ms][š„/tname:main/tid:1][coroutine:unnamed] Example where the server is aborted prior to finishing:
[elapsed: 65ms][š„/tname:main/tid:1][coroutine:unnamed] Starting server
[elapsed: 73ms][ā¶/tname:DefaultDispatcher-worker-1/tid:20][coroutine:ServerWork-1] Running server work in thread: DefaultDispatcher-worker-1
[elapsed: 74ms][ā·/tname:DefaultDispatcher-worker-2/tid:21][coroutine:ServerWork-2] Running additional server work in thread: DefaultDispatcher-worker-2
[elapsed: 1084ms][š„/tname:main/tid:1][coroutine:unnamed] Stopping server
[elapsed: 1087ms][š„/tname:main/tid:1][coroutine:unnamed] --------------------------------------------------------------------------------
[elapsed: 1087ms][š„/tname:main/tid:1][coroutine:unnamed] Example where the server has time to finish:
[elapsed: 1087ms][š„/tname:main/tid:1][coroutine:unnamed] Starting server
[elapsed: 1088ms][ā¶/tname:DefaultDispatcher-worker-1/tid:20][coroutine:ServerWork-1] Running server work in thread: DefaultDispatcher-worker-1
[elapsed: 1088ms][ā·/tname:DefaultDispatcher-worker-2/tid:21][coroutine:ServerWork-2] Running additional server work in thread: DefaultDispatcher-worker-2
[elapsed: 2594ms][ā·/tname:DefaultDispatcher-worker-2/tid:21][coroutine:ServerWork-2] ServerWork-2 completed
[elapsed: 3093ms][ā·/tname:DefaultDispatcher-worker-2/tid:21][coroutine:ServerWork-1] ServerWork-1 completed
[elapsed: 4089ms][š„/tname:main/tid:1][coroutine:unnamed] Stopping server
Cannot re-use scope
From Cannot Re Use Scope
Go to text ā
https://chatgpt.com/share/31be55da-2e7f-4dc8-9fc3-000384f58086
Sample - 1
import kotlinx.coroutines.*
fun main() = runBlocking {
val scope = CoroutineScope(Dispatchers.Default)
val job = scope.launch {
println("Job started")
delay(1000)
println("Job completed")
}
delay(500) // Wait for a while
scope.cancel() // Cancel the scope
// Attempt to launch a new job in the cancelled scope
val newJob = scope.launch {
println("New job started")
delay(1000)
println("New job completed")
}
newJob.invokeOnCompletion { exception ->
if (exception is CancellationException) {
println("New job was cancelled due to scope cancellation")
} else if (exception != null) {
println("New job completed with exception: $exception")
} else {
println("New job completed successfully")
}
}
// Wait for all jobs to complete
joinAll(job, newJob)
}
Sample - 2
import kotlinx.coroutines.*
fun main() = runBlocking {
val scope = CoroutineScope(Dispatchers.Default)
val job = scope.launch {
println("Job started")
delay(1000)
println("Job completed")
}
delay(500) // Wait for a while
scope.cancel() // Cancel the scope
// Create a new scope and launch a new job
val newScope = CoroutineScope(Dispatchers.Default)
val newJob = newScope.launch {
println("New job started")
delay(1000)
println("New job completed")
}
// Wait for all jobs to complete
joinAll(job, newJob)
}
From Coroutine Job
Go to text ā
graph TD;
subgraph CoroutineScope
A[coroutineContext] -->|Has a| B(Parent Job)
A -->|Has a| C[Dispatcher]
end
B -->|Parent of| J1[Child Job 1]
B -->|Parent of| J2[Child Job 2]
B -->|Parent of| J3[Child Job 3]
J1 -->|Manages| D1[Coroutine 1]
J2 -->|Manages| D2[Coroutine 2]
J3 -->|Manages| D3[Coroutine 3]
D1 -->|Runs| E1[Task 1]
D2 -->|Runs| E2[Task 2]
D3 -->|Runs| E3[Task 3]
classDef blue fill:#3b82f6,stroke:#ffffff,stroke-width:2px;
classDef green fill:#10b981,stroke:#ffffff,stroke-width:2px;
classDef red fill:#ef4444,stroke:#ffffff,stroke-width:2px;
class A blue;
class B green;
class D1,D2,D3 red;
Children
Backlinks