0
# Job Management
1
2
Lifecycle management for coroutines providing hierarchical cancellation, completion tracking, and structured concurrency with parent-child relationships.
3
4
## Capabilities
5
6
### Job Interface
7
8
Represents a cancellable background job with a well-defined lifecycle and states.
9
10
```kotlin { .api }
11
interface Job : CoroutineContext.Element {
12
/** True if job is active and running */
13
val isActive: Boolean
14
15
/** True if job has completed (successfully or with failure) */
16
val isCompleted: Boolean
17
18
/** True if job was cancelled */
19
val isCancelled: Boolean
20
21
/** Sequence of all child jobs */
22
val children: Sequence<Job>
23
24
/** Starts the job if it was created in lazy state */
25
fun start(): Boolean
26
27
/** Cancels the job with optional cause */
28
fun cancel(cause: CancellationException? = null)
29
30
/** Suspends until job completion */
31
suspend fun join()
32
33
/** Select clause for join operation */
34
val onJoin: SelectClause0
35
36
/** Registers completion handler */
37
fun invokeOnCompletion(handler: CompletionHandler): DisposableHandle
38
39
/** Cancels job and suspends until completion */
40
suspend fun cancelAndJoin()
41
}
42
43
typealias CompletionHandler = (cause: Throwable?) -> Unit
44
```
45
46
**Job States:**
47
48
| State | isActive | isCompleted | isCancelled |
49
|-------|----------|-------------|-------------|
50
| New (lazy) | `false` | `false` | `false` |
51
| Active | `true` | `false` | `false` |
52
| Completing | `true` | `false` | `false` |
53
| Cancelling | `false` | `false` | `true` |
54
| Cancelled | `false` | `true` | `true` |
55
| Completed | `false` | `true` | `false` |
56
57
**Usage Examples:**
58
59
```kotlin
60
import kotlinx.coroutines.*
61
62
fun main() = runBlocking {
63
// Basic job lifecycle
64
val job = launch {
65
repeat(5) { i ->
66
println("Working $i")
67
delay(500)
68
}
69
}
70
71
delay(1500) // Let it work for a while
72
println("Job state - Active: ${job.isActive}, Completed: ${job.isCompleted}")
73
74
job.cancel() // Cancel the job
75
job.join() // Wait for cancellation to complete
76
77
println("Job state - Active: ${job.isActive}, Cancelled: ${job.isCancelled}")
78
}
79
80
// Completion handler example
81
fun jobWithCompletionHandler() = runBlocking {
82
val job = launch {
83
try {
84
delay(1000)
85
println("Job completed normally")
86
} catch (e: CancellationException) {
87
println("Job was cancelled")
88
throw e
89
}
90
}
91
92
job.invokeOnCompletion { cause ->
93
if (cause != null) {
94
println("Job completed with exception: $cause")
95
} else {
96
println("Job completed successfully")
97
}
98
}
99
100
delay(500)
101
job.cancel()
102
job.join()
103
}
104
```
105
106
### Deferred Interface
107
108
A Job that produces a result value, created by `async` coroutine builder.
109
110
```kotlin { .api }
111
interface Deferred<out T> : Job {
112
/** Suspends until result is available and returns it */
113
suspend fun await(): T
114
115
/** Gets result if completed, throws if not completed or failed */
116
fun getCompleted(): T
117
118
/** Returns completion exception or null if completed successfully */
119
fun getCompletionExceptionOrNull(): Throwable?
120
121
/** Select clause for await operation */
122
val onAwait: SelectClause1<T>
123
}
124
```
125
126
**Usage Examples:**
127
128
```kotlin
129
import kotlinx.coroutines.*
130
131
fun main() = runBlocking {
132
// Single deferred
133
val deferred = async {
134
delay(1000)
135
"Hello, World!"
136
}
137
138
val result = deferred.await()
139
println(result)
140
141
// Multiple concurrent operations
142
val deferredList = List(5) { i ->
143
async {
144
delay((i + 1) * 100L)
145
"Result $i"
146
}
147
}
148
149
val results = deferredList.awaitAll()
150
println("All results: $results")
151
152
// Error handling
153
val faultyDeferred = async {
154
delay(100)
155
throw RuntimeException("Something went wrong")
156
}
157
158
try {
159
faultyDeferred.await()
160
} catch (e: RuntimeException) {
161
println("Caught exception: ${e.message}")
162
}
163
}
164
165
// Getting completed result without suspending
166
fun checkCompletedResult() = runBlocking {
167
val deferred = async {
168
delay(100)
169
42
170
}
171
172
delay(200) // Ensure completion
173
174
if (deferred.isCompleted) {
175
val result = deferred.getCompleted()
176
println("Result: $result")
177
}
178
}
179
```
180
181
### CompletableJob
182
183
A Job that can be completed manually, created with `Job()` factory function.
184
185
```kotlin { .api }
186
interface CompletableJob : Job {
187
/** Completes the job successfully */
188
fun complete(): Boolean
189
190
/** Completes the job with exception */
191
fun completeExceptionally(exception: Throwable): Boolean
192
}
193
194
/** Creates a new CompletableJob */
195
fun Job(parent: Job? = null): CompletableJob
196
```
197
198
**Usage Examples:**
199
200
```kotlin
201
import kotlinx.coroutines.*
202
203
fun main() = runBlocking {
204
// Manual job completion
205
val job = Job()
206
207
launch {
208
job.join()
209
println("Job completed!")
210
}
211
212
delay(1000)
213
job.complete() // Manually complete the job
214
215
// CompletableJob with parent
216
val parentJob = Job()
217
val childJob = Job(parentJob)
218
219
launch {
220
childJob.join()
221
println("Child job completed")
222
}
223
224
launch {
225
parentJob.join()
226
println("Parent job completed")
227
}
228
229
childJob.complete()
230
parentJob.complete()
231
}
232
233
// Error completion example
234
fun errorCompletionExample() = runBlocking {
235
val job = Job()
236
237
launch {
238
try {
239
job.join()
240
println("Should not reach here")
241
} catch (e: Exception) {
242
println("Job failed with: ${e.message}")
243
}
244
}
245
246
delay(100)
247
job.completeExceptionally(RuntimeException("Manual failure"))
248
}
249
```
250
251
### SupervisorJob
252
253
A special job that doesn't cancel its parent when its children fail, enabling supervisor pattern for fault tolerance.
254
255
```kotlin { .api }
256
/** Creates a supervisor job that doesn't propagate child failures */
257
fun SupervisorJob(parent: Job? = null): CompletableJob
258
259
/** Creates a supervisor scope where child failures don't cancel siblings */
260
suspend fun <T> supervisorScope(
261
block: suspend CoroutineScope.() -> T
262
): T
263
```
264
265
**Usage Examples:**
266
267
```kotlin
268
import kotlinx.coroutines.*
269
270
fun main() = runBlocking {
271
// SupervisorJob example
272
val supervisor = SupervisorJob()
273
274
launch(supervisor) {
275
launch {
276
delay(100)
277
throw RuntimeException("Child 1 failed")
278
}
279
280
launch {
281
delay(200)
282
println("Child 2 completed successfully")
283
}
284
285
launch {
286
delay(300)
287
println("Child 3 completed successfully")
288
}
289
}
290
291
delay(500)
292
supervisor.complete()
293
}
294
295
// supervisorScope example
296
suspend fun processItems(items: List<String>) = supervisorScope {
297
items.map { item ->
298
async {
299
if (item == "fail") {
300
throw RuntimeException("Failed to process $item")
301
}
302
"Processed $item"
303
}
304
}.mapNotNull { deferred ->
305
try {
306
deferred.await()
307
} catch (e: Exception) {
308
println("Item processing failed: ${e.message}")
309
null // Continue with other items
310
}
311
}
312
}
313
```
314
315
### Job Hierarchy and Cancellation
316
317
Understanding parent-child relationships and cancellation propagation.
318
319
```kotlin { .api }
320
/** Extension property to get job from coroutine context */
321
val CoroutineContext.job: Job
322
323
/** Extension property to check if context is active */
324
val CoroutineContext.isActive: Boolean
325
326
/** Ensures the context is active, throws CancellationException if cancelled */
327
fun CoroutineContext.ensureActive()
328
329
/** Cancellation exception for cooperative cancellation */
330
class CancellationException(
331
message: String? = null,
332
cause: Throwable? = null
333
) : IllegalStateException(message, cause)
334
```
335
336
**Usage Examples:**
337
338
```kotlin
339
import kotlinx.coroutines.*
340
341
fun main() = runBlocking {
342
// Parent-child cancellation
343
val parentJob = launch {
344
val child1 = launch {
345
try {
346
repeat(10) { i ->
347
delay(100)
348
println("Child 1: $i")
349
}
350
} catch (e: CancellationException) {
351
println("Child 1 cancelled")
352
throw e
353
}
354
}
355
356
val child2 = launch {
357
try {
358
repeat(10) { i ->
359
delay(150)
360
println("Child 2: $i")
361
}
362
} catch (e: CancellationException) {
363
println("Child 2 cancelled")
364
throw e
365
}
366
}
367
368
delay(500)
369
println("Parent completing")
370
}
371
372
delay(300)
373
parentJob.cancel() // Cancels all children too
374
parentJob.join()
375
}
376
377
// Cooperative cancellation
378
suspend fun cooperativeCancellation() {
379
repeat(1000) { i ->
380
// Check for cancellation
381
if (!coroutineContext.isActive) {
382
println("Detected cancellation at iteration $i")
383
return
384
}
385
386
// Or use ensureActive() which throws CancellationException
387
coroutineContext.ensureActive()
388
389
// Simulate work
390
Thread.sleep(10)
391
}
392
}
393
```
394
395
## Types
396
397
### DisposableHandle
398
399
Handle for cleanup operations that can be disposed.
400
401
```kotlin { .api }
402
interface DisposableHandle {
403
/** Disposes of the resource */
404
fun dispose()
405
}
406
```
407
408
### Select Clause Types
409
410
Types used for select expressions in coroutine operations.
411
412
```kotlin { .api }
413
/** Base interface for select clauses */
414
sealed interface SelectClause
415
416
/** Select clause without parameters that doesn't select any value */
417
sealed interface SelectClause0 : SelectClause
418
419
/** Select clause without parameters that selects value of type T */
420
sealed interface SelectClause1<out T> : SelectClause
421
422
/** Select clause with parameter P that selects value of type Q */
423
sealed interface SelectClause2<in P, out Q> : SelectClause
424
```
425
426
### CoroutineContext Elements
427
428
Job-related context elements for coroutine management.
429
430
```kotlin { .api }
431
/** Context element key for Job */
432
object Job : CoroutineContext.Key<Job>
433
434
/** Creates a new job context element */
435
fun Job(): CompletableJob
436
```