MapTo Either silent fail when it's not matched - scala

I have the following code that silently fail without catching any error:
(actor ? GetRowCount()).mapTo[Either[Rejection, Long]] map {
case Left(x) => ctx.reject(x)
case Right(totalRows) => ctx.complete(totalRows)
}
When GetRowCount() does not return a Long, but a String for instance, no error was caught and it just silently fail.
I am thinking to use the following:
(actor ? GetRowCount()).mapTo[Either[Rejection, Any]] map {
case Left(x) => ctx.reject(x)
case Right(totalRows: Long) => ctx.complete(totalRows)
case _ => ctx.reject(Rejection("Type mismatch"))
}
But is there a better answer?

I would use recover or recoverWith
(actor ? GetRowCount).mapTo[Either[Rejection, Long]] map {
case Left(x) => ctx.reject(x)
case Right(totalRows) => ctx.complete(totalRows)
} recover {
case e: Throwable =>
logger.error(e, "Some thing wrong while performing ask")
//throw an error or return something here
}

Related

How to write a Future method in foreach concisely

I'm a beginner in Scala. Is there a concise way to write the following nested case statement?
def delete(
client : TwitterRestClient,
userId : Long,
keyword : String) : Unit = {
client.userTimelineForUserId(userId).onComplete{
case Success(value) => {
value.data.filter(_.text.contains(keyword)).foreach(x => {
client.deleteTweet(x.id).onComplete{
case Success(value) => println(s"Success: $value")
case Failure(exception) => println(s"Fail: $exception")
}
})
}
case Failure(exception) => println(s"Fail:$exception")
}
Slightly different way using flatMap, sequencing Futures and using collect instead of filter and map:
def delete(
client : TwitterRestClient,
userId : Long,
keyword : String) : Unit = {
client
.userTimelineForUserId(userId)
.flatMap(ratedData => Future.sequence(ratedData.data.collect {
case tweet if tweet.text.contains(keyword) => client.deleteTweet(tweet.id)
}))
.onComplete {
case Success(value) => println(s"Success: $value")
case Failure(exception) => println(s"Fail: $exception")
}
}
I have only compiled the code, dint run it.

How to update elegantly the Failure exception of a Try?

I would like to update the Failure exception of a Try to provide a more understandable failure.
I successfully do this by using the following implementation:
case class NoDataAvailableException() extends Exception
[...]
Try(...) match {
case Success(f) => Success(f)
case Failure(_) => Failure(NoDataAvailableException())
}
But I think this implementation is not really elegant, so my question is:
Is there a way to do this more elegantly ?
You could use recoverWith with accepts a PartialFunction[Throwable, Try[U]]. This would allow you to map specific exceptions to successes or failures, as you wish.
case class MyException() extends Exception
Try(1 / 0) recoverWith {
case _: ArithmeticException => Failure(new MyException())
// other exceptions ...
}
You could also use an implicit class to add method of your own to Try that lets you specifically map exceptions.
implicit class TryExtension[A](t: Try[A]) {
def mapFailure(pf: PartialFunction[Throwable, Throwable]): Try[A] =
t.recoverWith(pf.andThen(Failure.apply))
}
scala> Try(1 / 0).mapFailure { case _ => new MyException }
res3: scala.util.Try[Int] = Failure(MyException)
You are looking for Try.recoverWith
Try(...) recoverWith {
case _ => Failure(NoDataAvailableException())
}
How about using try.recover or try.recoverWith?

How to write a function that handle exceptions from futures in Scala?

Several times in my application, I handle the errors of a future the same way.
For instance I do:
future map(r => println(r)) recover {
case arithmeticException => log("arithmetic exception")
case NonFatal(e) => log(e)
}
How can I extract a method from the recover part in order to reuse it elsewhere?
For instance, I would like to do something like:
def handleException(): PartialFunction[Throwable, Unit] = {
case arithmeticException => log("arithmetic exception")
case NonFatal(e) => log(e)
}
and use it like this:
future map(r => println(r)) recover { handleException() }
How can I do this?
val handleException: PartialFunction[Throwable, Unit] = {
case arithmeticException => log("arithmetic exception")
case NonFatal(e) => log(e)
}
future.map(println).recover(handleException)

Generic Try[T] function

I want to refactor some common error handling logic in a generic Try[T] handler, similar to this:
def handler[T](t: Try[T], successFunc: T => Unit) = {
t.map {
case Success(res) => { // type mismatch required T, found Any (in successFunc line)
//case Success(res: T) => { // Type abstract type pattern T is unchecked since it is eliminated by erasure
successFunc(res)
}
case Failure(e: CustomException) => {
// custom actions
}
case Failure(e) => {
// custom actions
}
}
}
Seems I can't match against the type T because of type erasure. But I can't pass an Any to successFunc.
How can I implement this function?
Mapping on a try applies a function to the value held by a success of that try, what you have there is not a Success or a Failure, it's a T, what you want is a match:
def handler[T](t: Try[T], successFunc: T => Unit) = {
t match {
case Success(res) =>
successFunc(res)
case Failure(e: FileNotFoundException) =>
case Failure(e) =>
}
}
The usage in your case of map would be:
t.map(someT => successFunc(someT))

Elegant way of getting the Int value form Future[Option[Int]]

Is there a more elegant way of getting the Int value from Future[Option[Int]] instead of using finalFuture.value.get.get.get?
This is what I have so far:
val finalFuture: Future[Option[Int]] = result.contents
finalFuture.onComplete {
case Success(value) => println(s"Got the callback with value = ", finalFuture.value.get.get.get)
case Failure(e) => e.printStackTrace
}
You could nest the match:
finalFuture.onComplete {
case Success(Some(value)) => println(s"Got the callback with value = ", value)
case Success(None) => ()
case Failure(e) => e.printStackTrace
}
You can use foreach to apply a A => Unit function to the value in Option[A], if it exists.
fut.onComplete {
case Success(opt) => opt.foreach { val =>
println(s"Got the callback with value = {}", val)
}
case Falure(ex) => ex.printStackTrace
}
You can use also the toOption of Try to get Option[Option[Int]] and then flatten to get Option[Int]
def printVal(finalFuture: Future[Option[Int]] ) = finalFuture.onComplete(
_.toOption.flatten.foreach(x=> println (s"got {}",x))
)
EDIT: That assuming you don't care about the stacktrace :)