Process Future[Try[Option]] in scala - scala

I have a method that returns Future[Try[Option[Int]]]. I want to extract value of Int for further computation. Any idea how to process it??

future.map(_.map(_.map(i => doSomethingWith(i))))

If you want use cats you can do fun (for certain definitions of fun) things like:
import scala.concurrent._
import scala.util._
import scala.concurrent.ExecutionContext.Implicits.global
import cats.Functor
import cats.instances.option._
import cats.implicits._
val x = Future { Try { Some(1) } } // your type
Functor[Future].compose[Try].compose[Option].map(x)(_ + 2)
This is suggested ONLY if you're already familiar with cats or scalaz.
Otherwise, you're great to go with any of the other valid answers here (I especially like the map-map-map one).

Just map the future and use match case to handle the different cases:
val result: Future[Try[Option[Int]]] = ???
result.map {
case Success(Some(r)) =>
println(s"Success. Result: $r")
//Further computation here
case Success(None) => //Success with None
case Failure(ex) => //Failed Try
}

Converting Future[Try[Option[Int]]] to Future[Int]
One hacky way is to convert the unfavourable results into failed future and flatMapping over.
Convert try failures to Future failures preserving the information that exception originated from Try and convert None to NoneFound exception.
val f: Future[Try[Option[Int]]] = ???
case class TryException(ex: Throwable) extends Exception(ex.getMessage)
case object NoneFound extends Exception("None found")
val result: Future[Int] = f.flatMap {
case Success(Some(value)) => Future.successful(value)
case Success(None) => Future.failed(NoneFound)
case Failure(th) => Future.failed(TryException(th))
}
result.map { extractedValue =>
processTheExtractedValue(extractedValue)
}.recover {
case NoneFound => "None case"
case TryException(th) => "try failures"
case th => "future failures"
}
Now in every case you know from where the exception has originated. In case of NoneFound exception you know Future and Try are successful but option is none. This way information is not lost and nested structure is flattened to Future[Int].
Now result type would be Future[Int]. Just use map, flatMap, recover and recoverWith to compose further actions.

If you really concerned about extraction see this, else go through the answer by #pamu to see how you actually use your Future.
Suppose your Future value is result.
Await.ready(result, 10.seconds).value.get.map { i => i.get}.get
Obviously this wont get through your failure and None cases and would throw exceptions and Await is not recommended.
So if you want to handle Failure and None case ->
val extractedValue = Await.ready(f, 10.seconds).value.get match {
case Success(i) => i match {
case Some(value) => value
case None => println("Handling None here")
}
case Failure(i) => println("Handling Failure here")
}

Related

How to handle unhandled exception throw in monix onErrorHandle

I am using monix tasks and i am trying to catch a Throwable and then convert to a custom error. I have removed/changed the code to be simple and relevant. This is the code (question follows after the code snippet):
import io.netty.handler.codec.http.HttpRequest
import monix.reactive.Observable
import io.netty.buffer.ByteBuf
import monix.eval.Task
import com.mypackage.Response
private[this] def handler(
request: HttpRequest,
body: Observable[ByteBuf]
): Task[Response] = {
val localPackage = for {
failfast <- Task.eval(1 / 0)
} yield failfast
// Failure case.
localPackage.onErrorRecoverWith {
case ex: ArithmeticException =>
print(s"LOG HERE^^^^^^^^^^^^^^^")
return Task.now(
Response(HttpResponseStatus.BAD_REQUEST,
None,
None)
)
}.runAsync
// Success case.
localPackage.map { x =>
x match {
case Right(cool) =>
Response(
HttpResponseStatus.OK,
None,
cool
)
case Left(doesntmatter) => ???
}
}
}
I am able to see the print statement but the expected Task.now(Response(... is not being returned. Instead the method that calls the handler method is throwing an error. How do i make it return the Task[Response] ?
The success case works, the failure case does not.
Edit #1 : Fix errors in scala code.
Edit #2 This is how I fixed it.
// Success case.
localPackage.map { x =>
x match {
case Right(cool) =>
Response(
HttpResponseStatus.OK,
None,
cool
)
case Left(doesntmatter) => ???
}
}.onErrorRecoverWith {
case ex: ArithmeticException =>
print(s"LOG HERE^^^^^^^^^^^^^^^")
return Task.now(
Response(HttpResponseStatus.BAD_REQUEST,
None,
None)
)
}
I was thinking in terms of future and forgot the lazy eval nature of task. Also I understood how the CancellableFuture value was being discarded in the failure task.
Several problems with your sample.
For one this code isn't valid Scala:
val localPackage = for {
failfast <- 1 / 0
} yield failfast
I guess you meant Task.eval(1 / 0).
Also onErrorHandle does not have a Task as a return type, you were probably thinking of onErrorHandleWith. And it's a pretty bad idea to give it a partial function (i.e. a function that can throw exceptions due to matching errors) — if you want to match on that error, then better alternatives are onErrorRecover and onErrorRecoverWith, which take partial functions as arguments.
So here's a sample:
import monix.eval._
import monix.execution.Scheduler.Implicits.global
val task = Task.eval(1 / 0).onErrorRecoverWith {
case _: ArithmeticException => Task.now(Int.MinValue)
}
task.runAsync.foreach(println)
//=> -2147483648
Hope this helps.

How to manage a set of Akka futures

I have a Set of Future[T] that I want to manage into a single object for a library I am writing. In my current implementation I'm using a Future.sequence to collect them all and wait until they've resolved so I can do futurey things on them (map, collect, filter). However this only gives me the ability to match on Success or Failure, which is not necessarily the case for the collection of futures I'm dealing with. Some will fail and some will succeed and I would like to be able to extract the values I can from those that succeed and collect the exceptions and errors on the others so that I can escalate them appropriately. In pseudo code it would be something like
Future.sequence(Set[Future[T]]) andThen {
case FullSuccess => "woot"
case SomeErrors => "well, that's still ok."
case FullErrors => "Ok, who's the wise guy."
}
What I'm really looking for is to have data where there is data and not have to return a complete failure if only 1 of the futures in the sequence has failed.
Thanks for the help.
Unfortunately there is no builtin helper for your case, but it's easy to create your own:
import scala.concurrent.{Await, Future}
import scala.util.{Failure, Success, Try}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.DurationInt
def sequenceOfTries[T](futures: Seq[Future[T]]): Future[Seq[Try[T]]] =
futures.foldLeft(Future.successful(List[Try[T]]())) {
case (accF, f) => accF.flatMap {
acc => f.map(v => Success(v) :: acc).recover { case ex => Failure(ex) :: acc }
}
}.map(_.reverse)
val v = Seq(
Future.successful(1),
Future.failed(new IllegalStateException("2")),
Future.successful(3),
Future.failed(new IllegalStateException("4"))
)
Await.result(sequenceOfTries(v), 1.second)
Results:
v: Seq[scala.concurrent.Future[Int]] = List(scala.concurrent.impl.Promise$KeptPromise#2416f7e5, scala.concurrent.impl.Promise$KeptPromise#2aaf675d, scala.concurrent.impl.Promise$KeptPromise#360d48f, scala.concurrent.impl.Promise$KeptPromise#230f8be2)
res0: Seq[scala.util.Try[Int]] = List(Success(1), Failure(java.lang.IllegalStateException: 2), Success(3), Failure(java.lang.IllegalStateException: 4))
UPD. Alternatively you can utilize Future.sequence like this (with same result):
def sequenceOfTries[T](futures: Seq[Future[T]]): Future[Seq[Try[T]]] =
Future.sequence(futures.map(_.map(x => Success(x)).recover { case ex => Failure(ex) }))

Scala Future error handling with Either

I am writing a wrapper for an API and I want to do error handling for applications problems. Each request returns a Future so in order to do this I see 2 options: using a Future[Either] or using exceptions to fail the future immediately.
Here is a snippet with both situations, response is a future with the return of the HTTP request:
def handleRequestEither: Future[Either[String, String]] = {
response.map {
case "good_string" => Right("Success")
case _ => Left("Failed")
}
}
def handleRequest: Future[String] = {
response.map {
case "good_string" => "Success"
case _ => throw new Exception("Failed")
}
}
And here is the snippet to get the result in both cases:
handleRequestEither.onComplete {
case Success(res) =>
res match {
case Right(rightRes) => println(s"Success $res")
case Left(leftRes) => println(s"Failure $res")
}
case Failure(ex) =>
println(s"Failure $ex")
}
handleRequest.onComplete {
case Success(res) => println(s"Success $res")
case Failure(ex) => println(s"Failure $ex")
}
I don't like to use exceptions, but using Future[Either] makes it much more verbose to get the response afterwards, and if I want to map the result into another object it gets even more complicated. Is this the way to go, or are there better alternatives?
Let me paraphrase Erik Meijer and consider the following table:
Consider then this two features of a language construct: arity (does it aggregate one or many items?) and mode (synchronous when blocking read operations until ready or asynchronous when not).
All of this imply that Try constructs and blocks manage the success or failure of the block generating the result synchronously. You'll control whether your resources provides the right answer without encountering problems (those described by exceptions).
On the other hand a Future is a kind of asynchronous Try. That means that it successfully completes when no problems (exceptions) has been found then notifying its subscribers. Hence, I don't think you should have a future of Either in this case, that is your second handleRequest implementation is the right way of using futures.
Finally, if what disturbs you is throwing an exception, you could follow the approach of Promises:
def handleRequest: Future[String] = {
val p = Promise[String]
response.map {
case "good_string" => p.success("Success")
case _ => p.failure(new Exception("Failed"))
}
p.future
}
Or:
case class Reason(msg: String) extends Exception
def handleRequest: Future[String] = {
val p = Promise[String]
response.map {
case "good_string" => p.success("Success")
case _ => p.failure(Reason("Invalid response"))
}
p.future
}
I'd rather use your second approach.
You could use special type for that: EitherT from the scalaz library.
It works with scalaz enhanced version of Either : \/
It could transform combination of any monad and \/ into a single monad. So using scalaz instances for scala.concurent.Future you could achieve the desired mix. And you could go further with monad transformers if you wish. Read this beautiful blog if you're interested.
Here not prettified but working with scalaz 7.1 example for you:
import scala.concurrent.duration.Duration
import scala.concurrent.{Await, Future}
import scalaz._
import scalaz.std.scalaFuture._
import EitherT._
import scala.concurrent.ExecutionContext.Implicits.global
object EitherFuture {
type ETFS[X] = EitherT[Future, String, X]
val IntResponse = "result (\\d+)".r
def parse(response: Future[String]) =
eitherT(response map {
case IntResponse(num) ⇒ \/-(num.toInt)
case _ ⇒ -\/("bad response")
})
def divideBy2(x: Validation[String, Int]) =
x.ensure("non divisible by 2")(_ % 2 == 0).map(_ / 2)
def handleResponse(response: Future[String]) = for {
num ← parse(response).validationed(divideBy2)
} yield s"half is $num"
def main(args: Array[String]) {
Map(
'good → "result 10",
'proper → "result 11",
'bad → "bad_string"
) foreach { case (key, str) ⇒
val response = Future(str)
val handled = handleResponse(response)
val result = Await.result(handled.run, Duration.Inf)
println(s"for $key response we have $result")
}
}
}

How to improve the code of "nested Try.. match "?

In my scala code, I have some nested Try() match {}, which look ugly:
import scala.util._
Try(convertJsonToObject[User]) match {
case Success(userJsonObj) =>
Try(saveToDb(userJsonObj.id)) match {
case Success(user) => Created("User saved")
case _ => InternalServerError("database error")
}
case _ => BadRequest("bad input")
}
Is there any better way of writing such code?
There's a bunch of ways to solve this problem. I'll give you one possibility. Consider this cleaned up version of your code:
trait Result
case class BadRequest(message:String) extends Result
case class InternalServerError(message:String) extends Result
case class Created(message:String) extends Result
def processRequest(json:String):Result = {
val result =
for{
user <- Try(parseJson(json))
savedUser <- Try(saveToDb(user))
} yield Created("saved")
result.recover{
case jp:JsonParsingException => BadRequest(jp.getMessage)
case other => InternalServerError(other.getMessage)
}.get
}
def parseJson(json:String):User = ...
def saveToDb(user:User):User = ...
The caveat to this code is that it assumes that you can differentiate the json parsing failure from the db failure by the exception each might yield. Not a bad assumption to make though. This code is very similar to a java try/catch block that catches different exception types and returns different results based on catching those different types.
One other nice thing about this approach is that you could just define a standard recovery Partial Function for all kinds of possible exceptions and use it throughout your controllers (which I'm assuming this code is) to eliminate duplicate code. Something like this:
object ExceptionHandling{
val StandardRecovery:PartialFunction[Throwable,Result] = {
case jp:JsonParsingException => BadRequest(jp.getMessage)
case sql:SQLException => InternalServerError(sql.getMessage)
case other => InternalServerError(other.getMessage)
}
}
And then in your controller:
import ExceptionHandling._
result.recover(StandardRecovery).get
Another approach is to define implicit reads for User (if using Play Framework) and then doing something like
someData.validate[User].map { user =>
saveToDb(user.id) match { // you can return Try from saveToDb
case Success(savedUser) => Created("User saved")
case Failure(exception) => InternalServerError("Database Error")
}
}.recoverTotal {
e => BadRequest(JsError.toFlatJson(e))
}
Try(convertJsonToObject[User]).map([your code]).toOption.getOrElse(fallback)

scala style - how to avoid having lots of nested map

Very often i end up with lots of nested .map and .getOrElse when validating several consecutives conditions
for example:
def save() = CORSAction { request =>
request.body.asJson.map { json =>
json.asOpt[Feature].map { feature =>
MaxEntitiyValidator.checkMaxEntitiesFeature(feature).map { rs =>
feature.save.map { feature =>
Ok(toJson(feature.update).toString)
}.getOrElse {
BadRequest(toJson(
Error(status = BAD_REQUEST, message = "Error creating feature entity")
))
}
}.getOrElse {
BadRequest(toJson(
Error(status = BAD_REQUEST, message = "You have already reached the limit of feature.")
))
}
}.getOrElse {
BadRequest(toJson(
Error(status = BAD_REQUEST, message = "Invalid feature entity")
))
}
}.getOrElse {
BadRequest(toJson(
Error(status = BAD_REQUEST, message = "Expecting JSON data")
))
}
}
You get the idea
I just wanted to know if there's some idiomatic way to keep it more clear
If you hadn't had to return a different message for the None case this would be an ideal use-case for for comprehension. In your case , you probably want to use the Validation monad, as the one you can find in Scalaz. Example ( http://scalaz.github.com/scalaz/scalaz-2.9.0-1-6.0/doc.sxr/scalaz/Validation.scala.html ).
In functional programming, you should not throw exceptions but let functions which can fail return an Either[A,B], where by convention A is the type of result in case of failure and B is the type of result in case of success. You can then match against Left(a) or Right(b) to handle, reespectively, the two cases.
You can think of the Validation monad as an extended Either[A,B] where applying subsequent functions to a Validation will either yield a result, or the first failure in the execution chain.
sealed trait Validation[+E, +A] {
import Scalaz._
def map[B](f: A => B): Validation[E, B] = this match {
case Success(a) => Success(f(a))
case Failure(e) => Failure(e)
}
def foreach[U](f: A => U): Unit = this match {
case Success(a) => f(a)
case Failure(e) =>
}
def flatMap[EE >: E, B](f: A => Validation[EE, B]): Validation[EE, B] = this match {
case Success(a) => f(a)
case Failure(e) => Failure(e)
}
def either : Either[E, A] = this match {
case Success(a) => Right(a)
case Failure(e) => Left(e)
}
def isSuccess : Boolean = this match {
case Success(_) => true
case Failure(_) => false
}
def isFailure : Boolean = !isSuccess
def toOption : Option[A] = this match {
case Success(a) => Some(a)
case Failure(_) => None
}
}
final case class Success[E, A](a: A) extends Validation[E, A]
final case class Failure[E, A](e: E) extends Validation[E, A]
Your code now can be refactored by using the Validation monad into three validation layers. You should basically replace your map with a validation like the following:
def jsonValidation(request:Request):Validation[BadRequest,String] = request.asJson match {
case None => Failure(BadRequest(toJson(
Error(status = BAD_REQUEST, message = "Expecting JSON data")
)
case Some(data) => Success(data)
}
def featureValidation(validatedJson:Validation[BadRequest,String]): Validation[BadRequest,Feature] = {
validatedJson.flatMap {
json=> json.asOpt[Feature] match {
case Some(feature)=> Success(feature)
case None => Failure( BadRequest(toJson(
Error(status = BAD_REQUEST, message = "Invalid feature entity")
)))
}
}
}
And then you chain them like the following featureValidation(jsonValidation(request))
This is a classic example of where using a monad can clean up your code. For example you could use Lift's Box, which is not tied to Lift in any way. Then your code would look something like this:
requestBox.flatMap(asJSON).flatMap(asFeature).flatMap(doSomethingWithFeature)
where asJson is a Function from a request to a Box[JSON] and asFeature is a function from a Feature to some other Box. The box can contain either a value, in which case flatMap calls the function with that value, or it can be an instance of Failure and in that case flatMap does not call the function passed to it.
If you had posted some example code that compiles, I could have posted an answer that compiles.
I tried this to see if pattern matching offered someway to adapt the submitted code sample (in style, if not literally) to something more coherent.
object MyClass {
case class Result(val datum: String)
case class Ok(val _datum: String) extends Result(_datum)
case class BadRequest(_datum: String) extends Result(_datum)
case class A {}
case class B(val a: Option[A])
case class C(val b: Option[B])
case class D(val c: Option[C])
def matcher(op: Option[D]) = {
(op,
op.getOrElse(D(None)).c,
op.getOrElse(D(None)).c.getOrElse(C(None)).b,
op.getOrElse(D(None)).c.getOrElse(C(None)).b.getOrElse(B(None)).a
) match {
case (Some(d), Some(c), Some(b), Some(a)) => Ok("Woo Hoo!")
case (Some(d), Some(c), Some(b), None) => BadRequest("Missing A")
case (Some(d), Some(c), None, None) => BadRequest("Missing B")
case (Some(d), None, None, None) => BadRequest("Missing C")
case (None, None, None, None) => BadRequest("Missing D")
case _ => BadRequest("Egads")
}
}
}
Clearly there are ways to write this more optimally; this is left as an exercise for the reader.
I agree with Edmondo suggestion of using for comprehension but not with the part about using a validation library (At least not anymore given the new features added to scala standard lib since 2012). From my experience with scala, dev that struggle to come up with nice statement with the standard lib will also end up doing the same of even worst when using libs like cats or scalaz. Maybe not at the same place, but ideally we would solve the issue rather than just moving it.
Here is your code rewritten with for comprehension and either that is part of scala standard lib :
def save() = CORSAction { request =>
// Helper to generate the error
def badRequest(message: String) = Error(status = BAD_REQUEST, message)
//Actual validation
val updateEither = for {
json <- request.body.asJson.toRight(badRequest("Expecting JSON data"))
feature <- json.asOpt[Feature].toRight(badRequest("Invalid feature entity"))
rs <- MaxEntitiyValidator
.checkMaxEntitiesFeature(feature)
.toRight(badRequest("You have already reached the limit"))
} yield toJson(feature.update).toString
// Turn the either into an OK/BadRequest
featureEither match {
case Right(update) => Ok(update)
case Left(error) => BadRequest(toJson(error))
}
}
Explanations
Error handling
I'm not sure how much you know about either but they are pretty similar in behaviour as Validation presented by Edmondo or Try object from the scala library. Main difference between those object regard their capability and behaviour with errors, but beside that they all can be mapped and flat mapped the same way.
You can also see that I use toRight to immediately convert the option into Either instead of doing it at the end. I see that java dev have the reflex to throw exception as far as they physically can, but they mostly do so because the try catch mechanism is unwieldy: in case of success, to get data out of a try block you either need to return them or put them in a variable initialized to null out of the block. But this is not the case is scala: you can map a try or an either, so in general, you get a more legible code if you turn results into error representation as soon as have identified it as they are identified as incorrect.
For comprehension
I also know that dev discovering scala are often quite puzzled by for comprehension. This is quite understandable as in most other language, for is only used for iteration over collections while is scala, it seem to use usable on a lot of unrelated types. In scala for is actually more nicer way to call the function flatMap. The compiler may decide to optimize it with map or foreach but it remain correct assume that you will get a flatMap behavior when you use for.
Calling flatMap on a collection will behave like the for each would in other language, so scala for may be used like a standard for when dealing with collection. But you can also use it on any other type of object that provide an implementation for flatMap with the correct signature. If your OK/BadRequest also implement the flatMap, you may be able to use in directly in the for comprehension instead of usong an intermediate Either representation.
For the people are not at ease with using for on anything that do not look like a collection, here is is how the function would look like if explicitly using flatMap instead of for :
def save() = CORSAction { request =>
def badRequest(message: String) = Error(status = BAD_REQUEST, message)
val updateEither = request.body.asJson.toRight(badRequest("Expecting JSON data"))
.flatMap { json =>
json
.asOpt[Feature]
.toRight(badRequest("Invalid feature entity"))
}
.flatMap { feature =>
MaxEntitiyValidator
.checkMaxEntitiesFeature(feature)
.map(_ => feature)
.toRight(badRequest("You have already reached the limit"))
}
.map { rs =>
toJson(feature.update).toString
}
featureEither match {
case Right(update) => Ok(update)
case Left(error) => BadRequest(toJson(error))
}
}
Note that in term of parameter scope, for behave live if the function where nested, not chained.
Conclusion
I think that more than not using the right framework or the right language feature, the main issue with the code your provided is how errors are dealt with. In general, you should not write error paths as after thought that you pile up at the end of the method. If you can deal with the error immediately as they occur, that allow you to move to something else. On the contrary, the more you push them back, the more you will have code with inextricable nesting. They are actually a materialization of all the pending error cases that scala expect you to deal with at some point.