diff --git a/akka-docs/src/main/paradox/stream/operators/Source-or-Flow/recover.md b/akka-docs/src/main/paradox/stream/operators/Source-or-Flow/recover.md index 84dd2d5adb..55dd917fc7 100644 --- a/akka-docs/src/main/paradox/stream/operators/Source-or-Flow/recover.md +++ b/akka-docs/src/main/paradox/stream/operators/Source-or-Flow/recover.md @@ -14,7 +14,12 @@ Allow sending of one last element downstream when a failure has happened upstrea ## Description -Allow sending of one last element downstream when a failure has happened upstream. +`recover` allows you to emit a final element and then complete the stream on an upstream failure. +Deciding which exceptions should be recovered is done through a `PartialFunction`. If an exception +does not have a @scala[matching case] @java[match defined] the stream is failed. + +Recovering can be useful if you want to gracefully complete a stream on failure while letting +downstream know that there was a failure. Throwing an exception inside `recover` _will_ be logged on ERROR level automatically. @@ -30,3 +35,21 @@ Throwing an exception inside `recover` _will_ be logged on ERROR level automatic @@@ +Below example demonstrates how `recover` gracefully complete a stream on failure. + +Scala +: @@snip [FlowErrorDocSpec.scala](/akka-docs/src/test/scala/docs/stream/FlowErrorDocSpec.scala) { #recover } + +Java +: @@snip [FlowErrorDocTest.java](/akka-docs/src/test/java/jdocs/stream/FlowErrorDocTest.java) { #recover } + +This will output: + +Scala +: @@snip [FlowErrorDocSpec.scala](/akka-docs/src/test/scala/docs/stream/FlowErrorDocSpec.scala) { #recover-output } + +Java +: @@snip [FlowErrorDocTest.java](/akka-docs/src/test/java/jdocs/stream/FlowErrorDocTest.java) { #recover-output } + +The output in the line `before failure` denotes the last successful element available from the upstream, +and the output in the line `on failure` denotes the element returns by partial function when upstream is failed. diff --git a/akka-docs/src/main/paradox/stream/stream-error.md b/akka-docs/src/main/paradox/stream/stream-error.md index cce687e437..589379b5ff 100644 --- a/akka-docs/src/main/paradox/stream/stream-error.md +++ b/akka-docs/src/main/paradox/stream/stream-error.md @@ -56,6 +56,10 @@ does not have a @scala[matching case] @java[match defined] the stream is failed. Recovering can be useful if you want to gracefully complete a stream on failure while letting downstream know that there was a failure. +Throwing an exception inside `recover` _will_ be logged on ERROR level automatically. + +More details in @ref[recover](./operators/Source-or-Flow/recover.md#recover) + Scala : @@snip [FlowErrorDocSpec.scala](/akka-docs/src/test/scala/docs/stream/FlowErrorDocSpec.scala) { #recover } diff --git a/akka-docs/src/test/java/jdocs/stream/FlowErrorDocTest.java b/akka-docs/src/test/java/jdocs/stream/FlowErrorDocTest.java index de33dbc567..2f3e840b34 100644 --- a/akka-docs/src/test/java/jdocs/stream/FlowErrorDocTest.java +++ b/akka-docs/src/test/java/jdocs/stream/FlowErrorDocTest.java @@ -142,10 +142,15 @@ public class FlowErrorDocTest extends AbstractJavaTest { Source.from(Arrays.asList(0, 1, 2, 3, 4, 5, 6)) .map( n -> { - if (n < 5) return n.toString(); - else throw new RuntimeException("Boom!"); + // assuming `4` and `5` are unexpected values that could throw exception + if (Arrays.asList(4, 5).contains(n)) + throw new RuntimeException(String.format("Boom! Bad value found: %s", n)); + else return n.toString(); }) - .recover(new PFBuilder().match(RuntimeException.class, ex -> "stream truncated").build()) + .recover( + new PFBuilder() + .match(RuntimeException.class, Throwable::getMessage) + .build()) .runForeach(System.out::println, system); // #recover @@ -155,9 +160,8 @@ public class FlowErrorDocTest extends AbstractJavaTest { 0 1 2 - 3 - 4 - stream truncated + 3 // last element before failure + Boom! Bad value found: 4 // first element on failure //#recover-output */ } diff --git a/akka-docs/src/test/scala/docs/stream/FlowErrorDocSpec.scala b/akka-docs/src/test/scala/docs/stream/FlowErrorDocSpec.scala index e2f5b005ce..e47ec5192f 100644 --- a/akka-docs/src/test/scala/docs/stream/FlowErrorDocSpec.scala +++ b/akka-docs/src/test/scala/docs/stream/FlowErrorDocSpec.scala @@ -91,11 +91,13 @@ class FlowErrorDocSpec extends AkkaSpec { "demonstrate recover" in { //#recover Source(0 to 6) - .map(n => - if (n < 5) n.toString - else throw new RuntimeException("Boom!")) + .map( + n => + // assuming `4` and `5` are unexpected values that could throw exception + if (List(4, 5).contains(n)) throw new RuntimeException(s"Boom! Bad value found: $n") + else n.toString) .recover { - case _: RuntimeException => "stream truncated" + case e: RuntimeException => e.getMessage } .runForeach(println) //#recover @@ -106,9 +108,8 @@ Output: 0 1 2 -3 -4 -stream truncated +3 // last element before failure +Boom! Bad value found: 4 // first element on failure //#recover-output */ }