blob: 08e63ea99451d2b66469519f2735ee47b4cd246d [file] [log] [blame] [view]
Roman Elizarov660c2d72020-02-14 13:18:37 +03001<!--- TEST_NAME ExceptionsGuideTest -->
hadihariri7db55532018-09-15 10:35:08 +02002
Prendotab8a559d2018-11-30 16:24:23 +03003**Table of contents**
hadihariri7db55532018-09-15 10:35:08 +02004
5<!--- TOC -->
6
Roman Elizarov3258e1f2019-08-22 20:08:48 +03007* [Exception Handling](#exception-handling)
hadihariri7db55532018-09-15 10:35:08 +02008 * [Exception propagation](#exception-propagation)
9 * [CoroutineExceptionHandler](#coroutineexceptionhandler)
10 * [Cancellation and exceptions](#cancellation-and-exceptions)
11 * [Exceptions aggregation](#exceptions-aggregation)
Roman Elizarov3258e1f2019-08-22 20:08:48 +030012 * [Supervision](#supervision)
13 * [Supervision job](#supervision-job)
14 * [Supervision scope](#supervision-scope)
15 * [Exceptions in supervised coroutines](#exceptions-in-supervised-coroutines)
hadihariri7db55532018-09-15 10:35:08 +020016
Roman Elizarov660c2d72020-02-14 13:18:37 +030017<!--- END -->
hadihariri7db55532018-09-15 10:35:08 +020018
Roman Elizarov3258e1f2019-08-22 20:08:48 +030019## Exception Handling
hadihariri7db55532018-09-15 10:35:08 +020020
hadihariri7db55532018-09-15 10:35:08 +020021
22This section covers exception handling and cancellation on exceptions.
23We already know that cancelled coroutine throws [CancellationException] in suspension points and that it
24is ignored by coroutines machinery. But what happens if an exception is thrown during cancellation or multiple children of the same
25coroutine throw an exception?
26
27### Exception propagation
28
29Coroutine builders come in two flavors: propagating exceptions automatically ([launch] and [actor]) or
30exposing them to users ([async] and [produce]).
Kenji Otsuka4c76c6f2018-10-12 07:27:08 +090031The former treat exceptions as unhandled, similar to Java's `Thread.uncaughtExceptionHandler`,
hadihariri7db55532018-09-15 10:35:08 +020032while the latter are relying on the user to consume the final
33exception, for example via [await][Deferred.await] or [receive][ReceiveChannel.receive]
Alexander Prendotacbeef102018-09-27 18:42:04 +030034([produce] and [receive][ReceiveChannel.receive] are covered later in [Channels](https://github.com/Kotlin/kotlinx.coroutines/blob/master/docs/channels.md) section).
hadihariri7db55532018-09-15 10:35:08 +020035
Inego6da0ccd2019-04-21 14:26:40 +070036It can be demonstrated by a simple example that creates coroutines in the [GlobalScope]:
hadihariri7db55532018-09-15 10:35:08 +020037
Alexander Prendotacbeef102018-09-27 18:42:04 +030038<div class="sample" markdown="1" theme="idea" data-highlight-only>
39
hadihariri7db55532018-09-15 10:35:08 +020040```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +030041import kotlinx.coroutines.*
42
43fun main() = runBlocking {
hadihariri7db55532018-09-15 10:35:08 +020044 val job = GlobalScope.launch {
45 println("Throwing exception from launch")
46 throw IndexOutOfBoundsException() // Will be printed to the console by Thread.defaultUncaughtExceptionHandler
47 }
48 job.join()
49 println("Joined failed job")
50 val deferred = GlobalScope.async {
51 println("Throwing exception from async")
52 throw ArithmeticException() // Nothing is printed, relying on user to call await
53 }
54 try {
55 deferred.await()
56 println("Unreached")
57 } catch (e: ArithmeticException) {
58 println("Caught ArithmeticException")
59 }
60}
61```
62
Alexander Prendotacbeef102018-09-27 18:42:04 +030063</div>
64
Inego69c26df2019-04-21 14:51:25 +070065> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-exceptions-01.kt).
hadihariri7db55532018-09-15 10:35:08 +020066
Alexander Prendotacbeef102018-09-27 18:42:04 +030067The output of this code is (with [debug](https://github.com/Kotlin/kotlinx.coroutines/blob/master/docs/coroutine-context-and-dispatchers.md#debugging-coroutines-and-threads)):
hadihariri7db55532018-09-15 10:35:08 +020068
69```text
70Throwing exception from launch
Roman Elizarov303708b2018-09-28 12:20:49 +030071Exception in thread "DefaultDispatcher-worker-2 @coroutine#2" java.lang.IndexOutOfBoundsException
hadihariri7db55532018-09-15 10:35:08 +020072Joined failed job
73Throwing exception from async
74Caught ArithmeticException
75```
76
77<!--- TEST EXCEPTION-->
78
79### CoroutineExceptionHandler
80
81But what if one does not want to print all exceptions to the console?
82[CoroutineExceptionHandler] context element is used as generic `catch` block of coroutine where custom logging or exception handling may take place.
83It is similar to using [`Thread.uncaughtExceptionHandler`](https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#setUncaughtExceptionHandler(java.lang.Thread.UncaughtExceptionHandler)).
84
85On JVM it is possible to redefine global exception handler for all coroutines by registering [CoroutineExceptionHandler] via
86[`ServiceLoader`](https://docs.oracle.com/javase/8/docs/api/java/util/ServiceLoader.html).
87Global exception handler is similar to
88[`Thread.defaultUncaughtExceptionHandler`](https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#setDefaultUncaughtExceptionHandler(java.lang.Thread.UncaughtExceptionHandler))
89which is used when no more specific handlers are registered.
90On Android, `uncaughtExceptionPreHandler` is installed as a global coroutine exception handler.
91
92[CoroutineExceptionHandler] is invoked only on exceptions which are not expected to be handled by the user,
93so registering it in [async] builder and the like of it has no effect.
94
Prendota65e6c8c2018-10-17 11:51:08 +030095<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
Alexander Prendotacbeef102018-09-27 18:42:04 +030096
hadihariri7db55532018-09-15 10:35:08 +020097```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +030098import kotlinx.coroutines.*
99
100fun main() = runBlocking {
101//sampleStart
hadihariri7db55532018-09-15 10:35:08 +0200102 val handler = CoroutineExceptionHandler { _, exception ->
103 println("Caught $exception")
104 }
105 val job = GlobalScope.launch(handler) {
106 throw AssertionError()
107 }
108 val deferred = GlobalScope.async(handler) {
109 throw ArithmeticException() // Nothing will be printed, relying on user to call deferred.await()
110 }
111 joinAll(job, deferred)
Prendota65e6c8c2018-10-17 11:51:08 +0300112//sampleEnd
hadihariri7db55532018-09-15 10:35:08 +0200113}
114```
115
Alexander Prendotacbeef102018-09-27 18:42:04 +0300116</div>
117
Inego69c26df2019-04-21 14:51:25 +0700118> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-exceptions-02.kt).
hadihariri7db55532018-09-15 10:35:08 +0200119
120The output of this code is:
121
122```text
123Caught java.lang.AssertionError
124```
125
126<!--- TEST-->
127
128### Cancellation and exceptions
129
130Cancellation is tightly bound with exceptions. Coroutines internally use `CancellationException` for cancellation, these
131exceptions are ignored by all handlers, so they should be used only as the source of additional debug information, which can
132be obtained by `catch` block.
Marek Langiewiczb6dd65c2019-10-18 12:10:27 +0200133When a coroutine is cancelled using [Job.cancel], it terminates, but it does not cancel its parent.
hadihariri7db55532018-09-15 10:35:08 +0200134
Prendota65e6c8c2018-10-17 11:51:08 +0300135<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
Alexander Prendotacbeef102018-09-27 18:42:04 +0300136
hadihariri7db55532018-09-15 10:35:08 +0200137```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300138import kotlinx.coroutines.*
139
140fun main() = runBlocking {
141//sampleStart
hadihariri7db55532018-09-15 10:35:08 +0200142 val job = launch {
143 val child = launch {
144 try {
145 delay(Long.MAX_VALUE)
146 } finally {
147 println("Child is cancelled")
148 }
149 }
150 yield()
151 println("Cancelling child")
152 child.cancel()
153 child.join()
154 yield()
155 println("Parent is not cancelled")
156 }
157 job.join()
Prendota65e6c8c2018-10-17 11:51:08 +0300158//sampleEnd
hadihariri7db55532018-09-15 10:35:08 +0200159}
160```
161
Alexander Prendotacbeef102018-09-27 18:42:04 +0300162</div>
163
Inego69c26df2019-04-21 14:51:25 +0700164> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-exceptions-03.kt).
hadihariri7db55532018-09-15 10:35:08 +0200165
166The output of this code is:
167
168```text
169Cancelling child
170Child is cancelled
171Parent is not cancelled
172```
173
174<!--- TEST-->
175
andrethielef605b262019-10-03 12:18:37 +0200176If a coroutine encounters an exception other than `CancellationException`, it cancels its parent with that exception.
hadihariri7db55532018-09-15 10:35:08 +0200177This behaviour cannot be overridden and is used to provide stable coroutines hierarchies for
Alexander Prendotacbeef102018-09-27 18:42:04 +0300178[structured concurrency](https://github.com/Kotlin/kotlinx.coroutines/blob/master/docs/composing-suspending-functions.md#structured-concurrency-with-async) which do not depend on
hadihariri7db55532018-09-15 10:35:08 +0200179[CoroutineExceptionHandler] implementation.
180The original exception is handled by the parent when all its children terminate.
181
182> This also a reason why, in these examples, [CoroutineExceptionHandler] is always installed to a coroutine
183that is created in [GlobalScope]. It does not make sense to install an exception handler to a coroutine that
184is launched in the scope of the main [runBlocking], since the main coroutine is going to be always cancelled
185when its child completes with exception despite the installed handler.
186
Prendota65e6c8c2018-10-17 11:51:08 +0300187<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
Alexander Prendotacbeef102018-09-27 18:42:04 +0300188
hadihariri7db55532018-09-15 10:35:08 +0200189```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300190import kotlinx.coroutines.*
191
192fun main() = runBlocking {
巳月55a48fb2018-10-31 18:27:47 +0800193//sampleStart
hadihariri7db55532018-09-15 10:35:08 +0200194 val handler = CoroutineExceptionHandler { _, exception ->
195 println("Caught $exception")
196 }
197 val job = GlobalScope.launch(handler) {
198 launch { // the first child
199 try {
200 delay(Long.MAX_VALUE)
201 } finally {
202 withContext(NonCancellable) {
203 println("Children are cancelled, but exception is not handled until all children terminate")
204 delay(100)
205 println("The first child finished its non cancellable block")
206 }
207 }
208 }
209 launch { // the second child
210 delay(10)
211 println("Second child throws an exception")
212 throw ArithmeticException()
213 }
214 }
215 job.join()
Prendota65e6c8c2018-10-17 11:51:08 +0300216//sampleEnd
hadihariri7db55532018-09-15 10:35:08 +0200217}
218```
219
Alexander Prendotacbeef102018-09-27 18:42:04 +0300220</div>
221
Inego69c26df2019-04-21 14:51:25 +0700222> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-exceptions-04.kt).
hadihariri7db55532018-09-15 10:35:08 +0200223
224The output of this code is:
225
226```text
227Second child throws an exception
228Children are cancelled, but exception is not handled until all children terminate
229The first child finished its non cancellable block
230Caught java.lang.ArithmeticException
231```
232<!--- TEST-->
233
234### Exceptions aggregation
235
236What happens if multiple children of a coroutine throw an exception?
237The general rule is "the first exception wins", so the first thrown exception is exposed to the handler.
238But that may cause lost exceptions, for example if coroutine throws an exception in its `finally` block.
239So, additional exceptions are suppressed.
240
241> One of the solutions would have been to report each exception separately,
242but then [Deferred.await] should have had the same mechanism to avoid behavioural inconsistency and this
Andrii Chubko57680672018-10-17 03:56:57 +0300243would cause implementation details of a coroutines (whether it had delegated parts of its work to its children or not)
hadihariri7db55532018-09-15 10:35:08 +0200244to leak to its exception handler.
245
Prendota65e6c8c2018-10-17 11:51:08 +0300246
hadihariri7db55532018-09-15 10:35:08 +0200247<!--- INCLUDE
Roman Elizarov0950dfa2018-07-13 10:33:25 +0300248import kotlinx.coroutines.exceptions.*
hadihariri7db55532018-09-15 10:35:08 +0200249-->
250
Prendota65e6c8c2018-10-17 11:51:08 +0300251<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
Alexander Prendotacbeef102018-09-27 18:42:04 +0300252
hadihariri7db55532018-09-15 10:35:08 +0200253```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300254import kotlinx.coroutines.*
255import java.io.*
256
257fun main() = runBlocking {
hadihariri7db55532018-09-15 10:35:08 +0200258 val handler = CoroutineExceptionHandler { _, exception ->
Roman Elizarov54617b72018-09-28 17:42:44 +0300259 println("Caught $exception with suppressed ${exception.suppressed.contentToString()}")
hadihariri7db55532018-09-15 10:35:08 +0200260 }
261 val job = GlobalScope.launch(handler) {
262 launch {
263 try {
264 delay(Long.MAX_VALUE)
265 } finally {
266 throw ArithmeticException()
267 }
268 }
269 launch {
Roman Elizarov938c5e92018-09-28 16:10:09 +0300270 delay(100)
hadihariri7db55532018-09-15 10:35:08 +0200271 throw IOException()
272 }
273 delay(Long.MAX_VALUE)
274 }
Prendota65e6c8c2018-10-17 11:51:08 +0300275 job.join()
hadihariri7db55532018-09-15 10:35:08 +0200276}
277```
278
Alexander Prendotacbeef102018-09-27 18:42:04 +0300279</div>
280
Inego69c26df2019-04-21 14:51:25 +0700281> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-exceptions-05.kt).
hadihariri7db55532018-09-15 10:35:08 +0200282
Roman Elizarov54617b72018-09-28 17:42:44 +0300283> Note: This above code will work properly only on JDK7+ that supports `suppressed` exceptions
284
hadihariri7db55532018-09-15 10:35:08 +0200285The output of this code is:
286
287```text
288Caught java.io.IOException with suppressed [java.lang.ArithmeticException]
289```
290
291<!--- TEST-->
292
293> Note, this mechanism currently works only on Java version 1.7+.
294Limitation on JS and Native is temporary and will be fixed in the future.
295
296Cancellation exceptions are transparent and unwrapped by default:
297
Prendota65e6c8c2018-10-17 11:51:08 +0300298<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
Alexander Prendotacbeef102018-09-27 18:42:04 +0300299
hadihariri7db55532018-09-15 10:35:08 +0200300```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300301import kotlinx.coroutines.*
302import java.io.*
303
304fun main() = runBlocking {
305//sampleStart
hadihariri7db55532018-09-15 10:35:08 +0200306 val handler = CoroutineExceptionHandler { _, exception ->
307 println("Caught original $exception")
308 }
309 val job = GlobalScope.launch(handler) {
310 val inner = launch {
311 launch {
312 launch {
313 throw IOException()
314 }
315 }
316 }
317 try {
318 inner.join()
Vsevolod Tolstopyatova2d80882018-09-24 19:51:49 +0300319 } catch (e: CancellationException) {
320 println("Rethrowing CancellationException with original cause")
hadihariri7db55532018-09-15 10:35:08 +0200321 throw e
322 }
323 }
324 job.join()
Prendota65e6c8c2018-10-17 11:51:08 +0300325//sampleEnd
hadihariri7db55532018-09-15 10:35:08 +0200326}
327```
328
Alexander Prendotacbeef102018-09-27 18:42:04 +0300329</div>
330
Inego69c26df2019-04-21 14:51:25 +0700331> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-exceptions-06.kt).
hadihariri7db55532018-09-15 10:35:08 +0200332
333The output of this code is:
334
335```text
Vsevolod Tolstopyatova2d80882018-09-24 19:51:49 +0300336Rethrowing CancellationException with original cause
hadihariri7db55532018-09-15 10:35:08 +0200337Caught original java.io.IOException
338```
339<!--- TEST-->
Roman Elizarov99c28aa2018-09-23 18:42:36 +0300340
Roman Elizarov3258e1f2019-08-22 20:08:48 +0300341### Supervision
Vsevolod Tolstopyatov49f25a52018-09-28 13:34:10 +0300342
343As we have studied before, cancellation is a bidirectional relationship propagating through the whole
344coroutines hierarchy. But what if unidirectional cancellation is required?
345
Aaron Stacy2fe443b2019-03-24 20:00:36 -0500346A good example of such a requirement is a UI component with the job defined in its scope. If any of the UI's child tasks
347have failed, it is not always necessary to cancel (effectively kill) the whole UI component,
348but if UI component is destroyed (and its job is cancelled), then it is necessary to fail all child jobs as their results are no longer required.
Vsevolod Tolstopyatov49f25a52018-09-28 13:34:10 +0300349
350Another example is a server process that spawns several children jobs and needs to _supervise_
351their execution, tracking their failures and restarting just those children jobs that had failed.
352
Roman Elizarov3258e1f2019-08-22 20:08:48 +0300353#### Supervision job
Vsevolod Tolstopyatov49f25a52018-09-28 13:34:10 +0300354
355For these purposes [SupervisorJob][SupervisorJob()] can be used. It is similar to a regular [Job][Job()] with the only exception that cancellation is propagated
356only downwards. It is easy to demonstrate with an example:
357
Vsevolod Tolstopyatov49f25a52018-09-28 13:34:10 +0300358<div class="sample" markdown="1" theme="idea" data-highlight-only>
359
360```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300361import kotlinx.coroutines.*
362
363fun main() = runBlocking {
Vsevolod Tolstopyatov49f25a52018-09-28 13:34:10 +0300364 val supervisor = SupervisorJob()
365 with(CoroutineScope(coroutineContext + supervisor)) {
Vadym Od9819662018-10-19 16:16:57 -0500366 // launch the first child -- its exception is ignored for this example (don't do this in practice!)
Vsevolod Tolstopyatov49f25a52018-09-28 13:34:10 +0300367 val firstChild = launch(CoroutineExceptionHandler { _, _ -> }) {
368 println("First child is failing")
369 throw AssertionError("First child is cancelled")
370 }
371 // launch the second child
372 val secondChild = launch {
373 firstChild.join()
374 // Cancellation of the first child is not propagated to the second child
375 println("First child is cancelled: ${firstChild.isCancelled}, but second one is still active")
376 try {
377 delay(Long.MAX_VALUE)
378 } finally {
379 // But cancellation of the supervisor is propagated
380 println("Second child is cancelled because supervisor is cancelled")
381 }
382 }
383 // wait until the first child fails & completes
384 firstChild.join()
385 println("Cancelling supervisor")
386 supervisor.cancel()
387 secondChild.join()
388 }
389}
390```
391
392</div>
393
Inego69c26df2019-04-21 14:51:25 +0700394> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-supervision-01.kt).
Vsevolod Tolstopyatov49f25a52018-09-28 13:34:10 +0300395
396The output of this code is:
397
398```text
399First child is failing
400First child is cancelled: true, but second one is still active
401Cancelling supervisor
402Second child is cancelled because supervisor is cancelled
403```
404<!--- TEST-->
405
406
Roman Elizarov3258e1f2019-08-22 20:08:48 +0300407#### Supervision scope
Vsevolod Tolstopyatov49f25a52018-09-28 13:34:10 +0300408
409For *scoped* concurrency [supervisorScope] can be used instead of [coroutineScope] for the same purpose. It propagates cancellation
410only in one direction and cancels all children only if it has failed itself. It also waits for all children before completion
411just like [coroutineScope] does.
412
Vsevolod Tolstopyatov49f25a52018-09-28 13:34:10 +0300413<div class="sample" markdown="1" theme="idea" data-highlight-only>
414
415```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300416import kotlin.coroutines.*
417import kotlinx.coroutines.*
418
419fun main() = runBlocking {
Vsevolod Tolstopyatov49f25a52018-09-28 13:34:10 +0300420 try {
421 supervisorScope {
422 val child = launch {
423 try {
424 println("Child is sleeping")
425 delay(Long.MAX_VALUE)
426 } finally {
427 println("Child is cancelled")
428 }
429 }
430 // Give our child a chance to execute and print using yield
431 yield()
432 println("Throwing exception from scope")
433 throw AssertionError()
434 }
435 } catch(e: AssertionError) {
436 println("Caught assertion error")
437 }
438}
439```
440
441</div>
442
Inego69c26df2019-04-21 14:51:25 +0700443> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-supervision-02.kt).
Vsevolod Tolstopyatov49f25a52018-09-28 13:34:10 +0300444
445The output of this code is:
446
447```text
448Child is sleeping
449Throwing exception from scope
450Child is cancelled
451Caught assertion error
452```
453<!--- TEST-->
454
Roman Elizarov3258e1f2019-08-22 20:08:48 +0300455#### Exceptions in supervised coroutines
Vsevolod Tolstopyatov49f25a52018-09-28 13:34:10 +0300456
457Another crucial difference between regular and supervisor jobs is exception handling.
458Every child should handle its exceptions by itself via exception handling mechanisms.
459This difference comes from the fact that child's failure is not propagated to the parent.
460
Vsevolod Tolstopyatov49f25a52018-09-28 13:34:10 +0300461<div class="sample" markdown="1" theme="idea" data-highlight-only>
462
463```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300464import kotlin.coroutines.*
465import kotlinx.coroutines.*
466
467fun main() = runBlocking {
Vsevolod Tolstopyatov49f25a52018-09-28 13:34:10 +0300468 val handler = CoroutineExceptionHandler { _, exception ->
469 println("Caught $exception")
470 }
471 supervisorScope {
472 val child = launch(handler) {
473 println("Child throws an exception")
474 throw AssertionError()
475 }
476 println("Scope is completing")
477 }
478 println("Scope is completed")
479}
480```
481
482</div>
483
Inego69c26df2019-04-21 14:51:25 +0700484> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-supervision-03.kt).
Vsevolod Tolstopyatov49f25a52018-09-28 13:34:10 +0300485
486The output of this code is:
487
488```text
489Scope is completing
490Child throws an exception
491Caught java.lang.AssertionError
492Scope is completed
493```
494<!--- TEST-->
495
Roman Elizarov99c28aa2018-09-23 18:42:36 +0300496<!--- MODULE kotlinx-coroutines-core -->
Roman Elizarov0950dfa2018-07-13 10:33:25 +0300497<!--- INDEX kotlinx.coroutines -->
498[CancellationException]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-cancellation-exception/index.html
499[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html
500[async]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/async.html
501[Deferred.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/await.html
502[GlobalScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-global-scope/index.html
503[CoroutineExceptionHandler]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-exception-handler/index.html
504[Job.cancel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/cancel.html
505[runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html
506[SupervisorJob()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-supervisor-job.html
507[Job()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job.html
508[supervisorScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/supervisor-scope.html
509[coroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/coroutine-scope.html
510<!--- INDEX kotlinx.coroutines.channels -->
511[actor]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/actor.html
512[produce]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/produce.html
513[ReceiveChannel.receive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/receive.html
Roman Elizarov99c28aa2018-09-23 18:42:36 +0300514<!--- END -->