2

I am trying to build reactive application with monix 3.0.0-RC1.

For instance a have a Seq of Int's, and the second element is wrong. I can use Oservable.raiseError(...) to handle this:

  Observable.fromIterable(Seq(1,2,3))
    .flatMap( i =>
      if (i == 2) Observable.raiseError(new Exception("Wrong i"))
      else Observable.pure(i)
    )
    .doOnNext(i => println(s"Processing $i"))
    .foreachL(i => println(s"Finished $i"))
    .onErrorHandle(_ => Task.unit)

I do not like thrown exception in the code above.

In the other hand I can use Scala's Either:

Observable.fromIterable(Seq(1,2,3))
  .map( i =>
    if (i == 2) Left("Wrong i")
    else Right(i)
  )
  .doOnNext(either => either.map( i => println(s"Processing $i") ))
  .foreachL(either => either.map( i => println(s"Finished $i") ))

But either => either.map(...) in every step in not cool.

What is the better way to handle errors?

Oleg
  • 899
  • 1
  • 8
  • 22
  • 1
    The exception is not really "thrown". It's sent through on the error channel as part of Observable's design for errors. Why do you not like it? The fact that you don't want to deal with it at every step is a hint that it should be done like the first example. – Alvaro Carrasco Apr 10 '19 at 21:37
  • As @AlvaroCarrasco said, the `Exception` is never thrown and your first example is using `Observable`s as they are ment to be used. – Markus Appel Apr 15 '19 at 13:23

2 Answers2

4

You can use collect if you only care about the right result, e.g.

val logError = {
  case Right(_) => Task.unit
  case Left(i) => Task.delay(println(s"An error occured $i"))
}

Observable.fromIterable(Seq(1,2,3))
  .map( i =>
    if (i == 2) Left("Wrong i")
    else Right(i)
  )
  .doOnNext(logError)
  .collect {
    case Right(value) => value
  }
  .foreachL(i => println(i))

atl
  • 326
  • 1
  • 9
2

If you want to drop the bad element, you can do it this way.

Observable.fromIterable(1 to 3)
      .mapEval(p => { if(i == 2) Task.raiseError(new Exception) 
                      else Task.now(i)
                    }.attempt )
      .collect { case Right(v) => v }
      .foreachL(println)
      .runToFuture

/*
1
3
*/

Basically keep using Task and attempt to turn the Task composition into Task[Either].

inmyth
  • 8,880
  • 4
  • 47
  • 52