blob: 409acd537e4e94a1134de2f331640e495890427e [file] [log] [blame] [view]
hadihariri7db55532018-09-15 10:35:08 +02001<!--- INCLUDE .*/example-([a-z]+)-([0-9a-z]+)\.kt
2/*
Roman Elizarovdb0ef0c2019-07-03 15:02:44 +03003 * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
hadihariri7db55532018-09-15 10:35:08 +02004 */
5
6// This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
Roman Elizarov0950dfa2018-07-13 10:33:25 +03007package kotlinx.coroutines.guide.$$1$$2
hadihariri7db55532018-09-15 10:35:08 +02008-->
Vsevolod Tolstopyatove50a0fa2019-01-28 11:34:24 +03009<!--- KNIT ../kotlinx-coroutines-core/jvm/test/guide/.*\.kt -->
10<!--- TEST_OUT ../kotlinx-coroutines-core/jvm/test/guide/test/ExceptionsGuideTest.kt
hadihariri7db55532018-09-15 10:35:08 +020011// This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
Roman Elizarov0950dfa2018-07-13 10:33:25 +030012package kotlinx.coroutines.guide.test
hadihariri7db55532018-09-15 10:35:08 +020013
14import org.junit.Test
15
16class ExceptionsGuideTest {
17-->
Prendotab8a559d2018-11-30 16:24:23 +030018**Table of contents**
hadihariri7db55532018-09-15 10:35:08 +020019
20<!--- TOC -->
21
Roman Elizarov3258e1f2019-08-22 20:08:48 +030022* [Exception Handling](#exception-handling)
hadihariri7db55532018-09-15 10:35:08 +020023 * [Exception propagation](#exception-propagation)
24 * [CoroutineExceptionHandler](#coroutineexceptionhandler)
25 * [Cancellation and exceptions](#cancellation-and-exceptions)
26 * [Exceptions aggregation](#exceptions-aggregation)
Roman Elizarov3258e1f2019-08-22 20:08:48 +030027 * [Supervision](#supervision)
28 * [Supervision job](#supervision-job)
29 * [Supervision scope](#supervision-scope)
30 * [Exceptions in supervised coroutines](#exceptions-in-supervised-coroutines)
hadihariri7db55532018-09-15 10:35:08 +020031
32<!--- END_TOC -->
33
Roman Elizarov3258e1f2019-08-22 20:08:48 +030034## Exception Handling
hadihariri7db55532018-09-15 10:35:08 +020035
hadihariri7db55532018-09-15 10:35:08 +020036
37This section covers exception handling and cancellation on exceptions.
38We already know that cancelled coroutine throws [CancellationException] in suspension points and that it
39is ignored by coroutines machinery. But what happens if an exception is thrown during cancellation or multiple children of the same
40coroutine throw an exception?
41
42### Exception propagation
43
44Coroutine builders come in two flavors: propagating exceptions automatically ([launch] and [actor]) or
45exposing them to users ([async] and [produce]).
Kenji Otsuka4c76c6f2018-10-12 07:27:08 +090046The former treat exceptions as unhandled, similar to Java's `Thread.uncaughtExceptionHandler`,
hadihariri7db55532018-09-15 10:35:08 +020047while the latter are relying on the user to consume the final
48exception, for example via [await][Deferred.await] or [receive][ReceiveChannel.receive]
Alexander Prendotacbeef102018-09-27 18:42:04 +030049([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 +020050
Inego6da0ccd2019-04-21 14:26:40 +070051It can be demonstrated by a simple example that creates coroutines in the [GlobalScope]:
hadihariri7db55532018-09-15 10:35:08 +020052
Alexander Prendotacbeef102018-09-27 18:42:04 +030053<div class="sample" markdown="1" theme="idea" data-highlight-only>
54
hadihariri7db55532018-09-15 10:35:08 +020055```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +030056import kotlinx.coroutines.*
57
58fun main() = runBlocking {
hadihariri7db55532018-09-15 10:35:08 +020059 val job = GlobalScope.launch {
60 println("Throwing exception from launch")
61 throw IndexOutOfBoundsException() // Will be printed to the console by Thread.defaultUncaughtExceptionHandler
62 }
63 job.join()
64 println("Joined failed job")
65 val deferred = GlobalScope.async {
66 println("Throwing exception from async")
67 throw ArithmeticException() // Nothing is printed, relying on user to call await
68 }
69 try {
70 deferred.await()
71 println("Unreached")
72 } catch (e: ArithmeticException) {
73 println("Caught ArithmeticException")
74 }
75}
76```
77
Alexander Prendotacbeef102018-09-27 18:42:04 +030078</div>
79
Inego69c26df2019-04-21 14:51:25 +070080> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-exceptions-01.kt).
hadihariri7db55532018-09-15 10:35:08 +020081
Alexander Prendotacbeef102018-09-27 18:42:04 +030082The 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 +020083
84```text
85Throwing exception from launch
Roman Elizarov303708b2018-09-28 12:20:49 +030086Exception in thread "DefaultDispatcher-worker-2 @coroutine#2" java.lang.IndexOutOfBoundsException
hadihariri7db55532018-09-15 10:35:08 +020087Joined failed job
88Throwing exception from async
89Caught ArithmeticException
90```
91
92<!--- TEST EXCEPTION-->
93
94### CoroutineExceptionHandler
95
96But what if one does not want to print all exceptions to the console?
97[CoroutineExceptionHandler] context element is used as generic `catch` block of coroutine where custom logging or exception handling may take place.
98It is similar to using [`Thread.uncaughtExceptionHandler`](https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#setUncaughtExceptionHandler(java.lang.Thread.UncaughtExceptionHandler)).
99
100On JVM it is possible to redefine global exception handler for all coroutines by registering [CoroutineExceptionHandler] via
101[`ServiceLoader`](https://docs.oracle.com/javase/8/docs/api/java/util/ServiceLoader.html).
102Global exception handler is similar to
103[`Thread.defaultUncaughtExceptionHandler`](https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#setDefaultUncaughtExceptionHandler(java.lang.Thread.UncaughtExceptionHandler))
104which is used when no more specific handlers are registered.
105On Android, `uncaughtExceptionPreHandler` is installed as a global coroutine exception handler.
106
107[CoroutineExceptionHandler] is invoked only on exceptions which are not expected to be handled by the user,
108so registering it in [async] builder and the like of it has no effect.
109
Prendota65e6c8c2018-10-17 11:51:08 +0300110<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
Alexander Prendotacbeef102018-09-27 18:42:04 +0300111
hadihariri7db55532018-09-15 10:35:08 +0200112```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300113import kotlinx.coroutines.*
114
115fun main() = runBlocking {
116//sampleStart
hadihariri7db55532018-09-15 10:35:08 +0200117 val handler = CoroutineExceptionHandler { _, exception ->
118 println("Caught $exception")
119 }
120 val job = GlobalScope.launch(handler) {
121 throw AssertionError()
122 }
123 val deferred = GlobalScope.async(handler) {
124 throw ArithmeticException() // Nothing will be printed, relying on user to call deferred.await()
125 }
126 joinAll(job, deferred)
Prendota65e6c8c2018-10-17 11:51:08 +0300127//sampleEnd
hadihariri7db55532018-09-15 10:35:08 +0200128}
129```
130
Alexander Prendotacbeef102018-09-27 18:42:04 +0300131</div>
132
Inego69c26df2019-04-21 14:51:25 +0700133> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-exceptions-02.kt).
hadihariri7db55532018-09-15 10:35:08 +0200134
135The output of this code is:
136
137```text
138Caught java.lang.AssertionError
139```
140
141<!--- TEST-->
142
143### Cancellation and exceptions
144
145Cancellation is tightly bound with exceptions. Coroutines internally use `CancellationException` for cancellation, these
146exceptions are ignored by all handlers, so they should be used only as the source of additional debug information, which can
147be obtained by `catch` block.
148When a coroutine is cancelled using [Job.cancel] without a cause, it terminates, but it does not cancel its parent.
149Cancelling without cause is a mechanism for parent to cancel its children without cancelling itself.
150
Prendota65e6c8c2018-10-17 11:51:08 +0300151<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
Alexander Prendotacbeef102018-09-27 18:42:04 +0300152
hadihariri7db55532018-09-15 10:35:08 +0200153```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300154import kotlinx.coroutines.*
155
156fun main() = runBlocking {
157//sampleStart
hadihariri7db55532018-09-15 10:35:08 +0200158 val job = launch {
159 val child = launch {
160 try {
161 delay(Long.MAX_VALUE)
162 } finally {
163 println("Child is cancelled")
164 }
165 }
166 yield()
167 println("Cancelling child")
168 child.cancel()
169 child.join()
170 yield()
171 println("Parent is not cancelled")
172 }
173 job.join()
Prendota65e6c8c2018-10-17 11:51:08 +0300174//sampleEnd
hadihariri7db55532018-09-15 10:35:08 +0200175}
176```
177
Alexander Prendotacbeef102018-09-27 18:42:04 +0300178</div>
179
Inego69c26df2019-04-21 14:51:25 +0700180> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-exceptions-03.kt).
hadihariri7db55532018-09-15 10:35:08 +0200181
182The output of this code is:
183
184```text
185Cancelling child
186Child is cancelled
187Parent is not cancelled
188```
189
190<!--- TEST-->
191
192If a coroutine encounters exception other than `CancellationException`, it cancels its parent with that exception.
193This behaviour cannot be overridden and is used to provide stable coroutines hierarchies for
Alexander Prendotacbeef102018-09-27 18:42:04 +0300194[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 +0200195[CoroutineExceptionHandler] implementation.
196The original exception is handled by the parent when all its children terminate.
197
198> This also a reason why, in these examples, [CoroutineExceptionHandler] is always installed to a coroutine
199that is created in [GlobalScope]. It does not make sense to install an exception handler to a coroutine that
200is launched in the scope of the main [runBlocking], since the main coroutine is going to be always cancelled
201when its child completes with exception despite the installed handler.
202
Prendota65e6c8c2018-10-17 11:51:08 +0300203<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
Alexander Prendotacbeef102018-09-27 18:42:04 +0300204
hadihariri7db55532018-09-15 10:35:08 +0200205```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300206import kotlinx.coroutines.*
207
208fun main() = runBlocking {
巳月55a48fb2018-10-31 18:27:47 +0800209//sampleStart
hadihariri7db55532018-09-15 10:35:08 +0200210 val handler = CoroutineExceptionHandler { _, exception ->
211 println("Caught $exception")
212 }
213 val job = GlobalScope.launch(handler) {
214 launch { // the first child
215 try {
216 delay(Long.MAX_VALUE)
217 } finally {
218 withContext(NonCancellable) {
219 println("Children are cancelled, but exception is not handled until all children terminate")
220 delay(100)
221 println("The first child finished its non cancellable block")
222 }
223 }
224 }
225 launch { // the second child
226 delay(10)
227 println("Second child throws an exception")
228 throw ArithmeticException()
229 }
230 }
231 job.join()
Prendota65e6c8c2018-10-17 11:51:08 +0300232//sampleEnd
hadihariri7db55532018-09-15 10:35:08 +0200233}
234```
235
Alexander Prendotacbeef102018-09-27 18:42:04 +0300236</div>
237
Inego69c26df2019-04-21 14:51:25 +0700238> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-exceptions-04.kt).
hadihariri7db55532018-09-15 10:35:08 +0200239
240The output of this code is:
241
242```text
243Second child throws an exception
244Children are cancelled, but exception is not handled until all children terminate
245The first child finished its non cancellable block
246Caught java.lang.ArithmeticException
247```
248<!--- TEST-->
249
250### Exceptions aggregation
251
252What happens if multiple children of a coroutine throw an exception?
253The general rule is "the first exception wins", so the first thrown exception is exposed to the handler.
254But that may cause lost exceptions, for example if coroutine throws an exception in its `finally` block.
255So, additional exceptions are suppressed.
256
257> One of the solutions would have been to report each exception separately,
258but then [Deferred.await] should have had the same mechanism to avoid behavioural inconsistency and this
Andrii Chubko57680672018-10-17 03:56:57 +0300259would 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 +0200260to leak to its exception handler.
261
Prendota65e6c8c2018-10-17 11:51:08 +0300262
hadihariri7db55532018-09-15 10:35:08 +0200263<!--- INCLUDE
Prendota65e6c8c2018-10-17 11:51:08 +0300264
Roman Elizarov0950dfa2018-07-13 10:33:25 +0300265import kotlinx.coroutines.exceptions.*
hadihariri7db55532018-09-15 10:35:08 +0200266-->
267
Prendota65e6c8c2018-10-17 11:51:08 +0300268<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
Alexander Prendotacbeef102018-09-27 18:42:04 +0300269
hadihariri7db55532018-09-15 10:35:08 +0200270```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300271import kotlinx.coroutines.*
272import java.io.*
273
274fun main() = runBlocking {
hadihariri7db55532018-09-15 10:35:08 +0200275 val handler = CoroutineExceptionHandler { _, exception ->
Roman Elizarov54617b72018-09-28 17:42:44 +0300276 println("Caught $exception with suppressed ${exception.suppressed.contentToString()}")
hadihariri7db55532018-09-15 10:35:08 +0200277 }
278 val job = GlobalScope.launch(handler) {
279 launch {
280 try {
281 delay(Long.MAX_VALUE)
282 } finally {
283 throw ArithmeticException()
284 }
285 }
286 launch {
Roman Elizarov938c5e92018-09-28 16:10:09 +0300287 delay(100)
hadihariri7db55532018-09-15 10:35:08 +0200288 throw IOException()
289 }
290 delay(Long.MAX_VALUE)
291 }
Prendota65e6c8c2018-10-17 11:51:08 +0300292 job.join()
hadihariri7db55532018-09-15 10:35:08 +0200293}
294```
295
Alexander Prendotacbeef102018-09-27 18:42:04 +0300296</div>
297
Inego69c26df2019-04-21 14:51:25 +0700298> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-exceptions-05.kt).
hadihariri7db55532018-09-15 10:35:08 +0200299
Roman Elizarov54617b72018-09-28 17:42:44 +0300300> Note: This above code will work properly only on JDK7+ that supports `suppressed` exceptions
301
hadihariri7db55532018-09-15 10:35:08 +0200302The output of this code is:
303
304```text
305Caught java.io.IOException with suppressed [java.lang.ArithmeticException]
306```
307
308<!--- TEST-->
309
310> Note, this mechanism currently works only on Java version 1.7+.
311Limitation on JS and Native is temporary and will be fixed in the future.
312
313Cancellation exceptions are transparent and unwrapped by default:
314
Prendota65e6c8c2018-10-17 11:51:08 +0300315<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
Alexander Prendotacbeef102018-09-27 18:42:04 +0300316
hadihariri7db55532018-09-15 10:35:08 +0200317```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300318import kotlinx.coroutines.*
319import java.io.*
320
321fun main() = runBlocking {
322//sampleStart
hadihariri7db55532018-09-15 10:35:08 +0200323 val handler = CoroutineExceptionHandler { _, exception ->
324 println("Caught original $exception")
325 }
326 val job = GlobalScope.launch(handler) {
327 val inner = launch {
328 launch {
329 launch {
330 throw IOException()
331 }
332 }
333 }
334 try {
335 inner.join()
Vsevolod Tolstopyatova2d80882018-09-24 19:51:49 +0300336 } catch (e: CancellationException) {
337 println("Rethrowing CancellationException with original cause")
hadihariri7db55532018-09-15 10:35:08 +0200338 throw e
339 }
340 }
341 job.join()
Prendota65e6c8c2018-10-17 11:51:08 +0300342//sampleEnd
hadihariri7db55532018-09-15 10:35:08 +0200343}
344```
345
Alexander Prendotacbeef102018-09-27 18:42:04 +0300346</div>
347
Inego69c26df2019-04-21 14:51:25 +0700348> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-exceptions-06.kt).
hadihariri7db55532018-09-15 10:35:08 +0200349
350The output of this code is:
351
352```text
Vsevolod Tolstopyatova2d80882018-09-24 19:51:49 +0300353Rethrowing CancellationException with original cause
hadihariri7db55532018-09-15 10:35:08 +0200354Caught original java.io.IOException
355```
356<!--- TEST-->
Roman Elizarov99c28aa2018-09-23 18:42:36 +0300357
Roman Elizarov3258e1f2019-08-22 20:08:48 +0300358### Supervision
Vsevolod Tolstopyatov49f25a52018-09-28 13:34:10 +0300359
360As we have studied before, cancellation is a bidirectional relationship propagating through the whole
361coroutines hierarchy. But what if unidirectional cancellation is required?
362
Aaron Stacy2fe443b2019-03-24 20:00:36 -0500363A 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
364have failed, it is not always necessary to cancel (effectively kill) the whole UI component,
365but 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 +0300366
367Another example is a server process that spawns several children jobs and needs to _supervise_
368their execution, tracking their failures and restarting just those children jobs that had failed.
369
Roman Elizarov3258e1f2019-08-22 20:08:48 +0300370#### Supervision job
Vsevolod Tolstopyatov49f25a52018-09-28 13:34:10 +0300371
372For these purposes [SupervisorJob][SupervisorJob()] can be used. It is similar to a regular [Job][Job()] with the only exception that cancellation is propagated
373only downwards. It is easy to demonstrate with an example:
374
Vsevolod Tolstopyatov49f25a52018-09-28 13:34:10 +0300375<div class="sample" markdown="1" theme="idea" data-highlight-only>
376
377```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300378import kotlinx.coroutines.*
379
380fun main() = runBlocking {
Vsevolod Tolstopyatov49f25a52018-09-28 13:34:10 +0300381 val supervisor = SupervisorJob()
382 with(CoroutineScope(coroutineContext + supervisor)) {
Vadym Od9819662018-10-19 16:16:57 -0500383 // launch the first child -- its exception is ignored for this example (don't do this in practice!)
Vsevolod Tolstopyatov49f25a52018-09-28 13:34:10 +0300384 val firstChild = launch(CoroutineExceptionHandler { _, _ -> }) {
385 println("First child is failing")
386 throw AssertionError("First child is cancelled")
387 }
388 // launch the second child
389 val secondChild = launch {
390 firstChild.join()
391 // Cancellation of the first child is not propagated to the second child
392 println("First child is cancelled: ${firstChild.isCancelled}, but second one is still active")
393 try {
394 delay(Long.MAX_VALUE)
395 } finally {
396 // But cancellation of the supervisor is propagated
397 println("Second child is cancelled because supervisor is cancelled")
398 }
399 }
400 // wait until the first child fails & completes
401 firstChild.join()
402 println("Cancelling supervisor")
403 supervisor.cancel()
404 secondChild.join()
405 }
406}
407```
408
409</div>
410
Inego69c26df2019-04-21 14:51:25 +0700411> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-supervision-01.kt).
Vsevolod Tolstopyatov49f25a52018-09-28 13:34:10 +0300412
413The output of this code is:
414
415```text
416First child is failing
417First child is cancelled: true, but second one is still active
418Cancelling supervisor
419Second child is cancelled because supervisor is cancelled
420```
421<!--- TEST-->
422
423
Roman Elizarov3258e1f2019-08-22 20:08:48 +0300424#### Supervision scope
Vsevolod Tolstopyatov49f25a52018-09-28 13:34:10 +0300425
426For *scoped* concurrency [supervisorScope] can be used instead of [coroutineScope] for the same purpose. It propagates cancellation
427only in one direction and cancels all children only if it has failed itself. It also waits for all children before completion
428just like [coroutineScope] does.
429
Vsevolod Tolstopyatov49f25a52018-09-28 13:34:10 +0300430<div class="sample" markdown="1" theme="idea" data-highlight-only>
431
432```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300433import kotlin.coroutines.*
434import kotlinx.coroutines.*
435
436fun main() = runBlocking {
Vsevolod Tolstopyatov49f25a52018-09-28 13:34:10 +0300437 try {
438 supervisorScope {
439 val child = launch {
440 try {
441 println("Child is sleeping")
442 delay(Long.MAX_VALUE)
443 } finally {
444 println("Child is cancelled")
445 }
446 }
447 // Give our child a chance to execute and print using yield
448 yield()
449 println("Throwing exception from scope")
450 throw AssertionError()
451 }
452 } catch(e: AssertionError) {
453 println("Caught assertion error")
454 }
455}
456```
457
458</div>
459
Inego69c26df2019-04-21 14:51:25 +0700460> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-supervision-02.kt).
Vsevolod Tolstopyatov49f25a52018-09-28 13:34:10 +0300461
462The output of this code is:
463
464```text
465Child is sleeping
466Throwing exception from scope
467Child is cancelled
468Caught assertion error
469```
470<!--- TEST-->
471
Roman Elizarov3258e1f2019-08-22 20:08:48 +0300472#### Exceptions in supervised coroutines
Vsevolod Tolstopyatov49f25a52018-09-28 13:34:10 +0300473
474Another crucial difference between regular and supervisor jobs is exception handling.
475Every child should handle its exceptions by itself via exception handling mechanisms.
476This difference comes from the fact that child's failure is not propagated to the parent.
477
Vsevolod Tolstopyatov49f25a52018-09-28 13:34:10 +0300478<div class="sample" markdown="1" theme="idea" data-highlight-only>
479
480```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300481import kotlin.coroutines.*
482import kotlinx.coroutines.*
483
484fun main() = runBlocking {
Vsevolod Tolstopyatov49f25a52018-09-28 13:34:10 +0300485 val handler = CoroutineExceptionHandler { _, exception ->
486 println("Caught $exception")
487 }
488 supervisorScope {
489 val child = launch(handler) {
490 println("Child throws an exception")
491 throw AssertionError()
492 }
493 println("Scope is completing")
494 }
495 println("Scope is completed")
496}
497```
498
499</div>
500
Inego69c26df2019-04-21 14:51:25 +0700501> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-supervision-03.kt).
Vsevolod Tolstopyatov49f25a52018-09-28 13:34:10 +0300502
503The output of this code is:
504
505```text
506Scope is completing
507Child throws an exception
508Caught java.lang.AssertionError
509Scope is completed
510```
511<!--- TEST-->
512
Roman Elizarov99c28aa2018-09-23 18:42:36 +0300513<!--- MODULE kotlinx-coroutines-core -->
Roman Elizarov0950dfa2018-07-13 10:33:25 +0300514<!--- INDEX kotlinx.coroutines -->
515[CancellationException]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-cancellation-exception/index.html
516[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html
517[async]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/async.html
518[Deferred.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/await.html
519[GlobalScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-global-scope/index.html
520[CoroutineExceptionHandler]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-exception-handler/index.html
521[Job.cancel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/cancel.html
522[runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html
523[SupervisorJob()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-supervisor-job.html
524[Job()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job.html
525[supervisorScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/supervisor-scope.html
526[coroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/coroutine-scope.html
527<!--- INDEX kotlinx.coroutines.channels -->
528[actor]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/actor.html
529[produce]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/produce.html
530[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 +0300531<!--- END -->