How to unwrap a Future[Either[Throwable,T ]] to Either[Throwable,T] - scala

I have a function(myFunc) in scala that gives Future[Either[Throwable,T ]] . Now I need to unwrap and get Either[Throwable,T ] out of it and pass to as an input parameter to another function (anotherFunc).
def myFunc(input: String): Future[Either[Throwable, HttpResponse]] = {
....
}
def anotherFunc(response: Either[Throwable, T]) # signature
anotherFunc(myFunc("some string"))
Normally we use map to transform a Future but thats not helping me here
myFunc("some string").map { _ =>
anotherFunc(_)
}
This causes problem with the return of the block from where I am calling .

You can't unwrap the value of a Future because a Future represents the result of an asynchronous computation that may or may not be available yet. By default, futures and non-blocking, encouraging the use of callbacks instead of typical blocking operations.
What you can do is either:
use combinators such as map, flatMap, filter to compose futures in a non-blocking way.
register a callback using the onComplete method, or foreach if you want to call a callback only when the Future completes successfully.
block the main thread using Await.result, if this is absolutely necessary, although is discouraged. If you want to transform the Future result or combine it with others, you should opt for the 2 previos non-blocking ways mentioned.
That being said. These are the preferred approaches:
def anotherFunc[T](response: Future[Either[Throwable, T]]) = {
response.onComplete {
case Failure(exception) => // process exception
case Success(value) => // process value
}
}
def anotherFunc2[T](response: Future[Either[Throwable, T]]) = {
response.map {
case Left(exception) => // process exception
case Right(value) => // process value
}
}
Then you can do:
anotherFunc(myFunc("some string"))
anotherFunc2(myFunc("some string"))
EDIT:
If you can't change the signature of anotherFunc[T](response: Either[Throwable, T]) then just do:
myFunc("some string").map(anotherFunc)

Related

Best practice to make cleanup after Scala Future is complete

I want to make some cleanup (like close db connection) after a Future is complete.
Currently I achieve it this way:
Future { ... } onComplete {
case Success(v) =>
// ...
conn.close()
case Failure(ex) =>
// ...
conn.close()
}
There's duplicate code and it's also tedious.
Is there any best practice to this?
Since the same action conn.close() is performed on both success and failure, consider executing it as a side-effect using andThen like so
Future { ... } andThen { _ => conn.close() }
Similarly, using onComplete we could do
Future { ... } onComplete { _ => conn.close() }
The difference between andThen and onComplete is that latter will return Unit, that is, discard the returned value of the Future.
The sad truth is that Scala Futures don't have this basic feature built in. I would therefore strongly suggest using a modern effect system like ZIO or cats-effect, both of which solve this problem and a myriad of others that Futures have. The easiest way to do what you want is to use the bracket method:
https://zio.dev/docs/overview/overview_handling_resources
Now bracket works great, but there's a way that usually works even better: the Managed type. It's virtually impossible to write code that leaks resources if you consistently use Managed when acquiring resources:
https://zio.dev/docs/datatypes/datatypes_managed
That said,if you absolutely must use Futures, you'll have to write your own try-finally equivalent. Or you can use mine:
def tryFinally[A](tryy: => Future[A])(finallyy: => Future[Any])(
implicit ec: ExecutionContext): Future[A] =
Future.fromTry(Try(tryy)).flatten.transformWith { t =>
finallyy.flatMap((_: Any) => Future.fromTry(t))
}
I like to use map, you can do something like this:
val mapped: Future[String] = future.map(_ => "OK").recover{case _ => "KO"}

Idiomatic way to handle side effect and return value in Scala functions

How would you construct a function in which you both want to do a side effect and return a value?
For example I would like the following function:
def futureFromHttpCall: Future[HttpResponse] =
doHttpCall.foreach(publishDomainEvent).returnOriginalFuture
(somehow I have a feeling that monads will come up so if that is the path Im somewhat familiar with cats if there is a solution for this problem there?)
The simplest thing I can think of is instead of "hiding" the side effect inside the Future[T] returning method, expose it as a continuation on the future:
def futureFromHttpCall: Future[HttpResponse] = doHttpCall
And then you could either onComplete on it as a side effect:
futureFromHttpCall.onComplete {
case Success(_) => publishDomainEvent
case Failure(e) => // Stuff
}
Making the effect explicit. Or if you're inside an actor system, you can can pipeTo the Future to your receive method and handle success / failure there.
I think your Future should only complete when all of your domain events are pushed. They should be a Future as well. Then you can use Future.sequence to wait for all of them to complete before returning.
Your question is a little unclear but i assume doHttpCall is a list of some type.
def doHttpCall(): Future[Seq[X]] = ???
def publishDomainEvent(x:X): Future[Unit] = ???
def futureFromHttpCall(): Future[Seq[X]] = {
val firstFuture = ???
firstFuture.flatMap { xs =>
val xxs: Seq[Future[Unit]]= xs.map(publishDomainEvent)
Future.sequence(xxs).map { _ => re }
}
}
All of this waiting can be pretty helpful when testing.

Pattern for responding with async result

I am trying to get the following example working:
def asyncTest = Action {
val willBeInt = Future {
Thread.sleep(5000)
100
}
willBeInt.onComplete({
case Success(value) => Ok(s"Value = $value")
case Failure(e) => Failure(e)
})
}
But I am getting an error about overloading a method:
Overloaded method value [apply] cannot be applied to (Unit)
I'm coming from a background in NodeJS and am struggling to figure out how these callbacks are supposed to work while simultaneously returning a result to appease the method signature.
Think of Action as a function that returns a promise, rather than as a function that accepts a callback. In scala terminology, you'll be returning a Future. Play's internals will be calling onComplete (or something similar) on their own (analagous to a javascript Promise's then function).
Specifically, your compilation error is due to the fact that onComplete returns Unit, when the Action block is expecting you to return a Future. You can use map to transform your willBeInt future into what Play is looking for:
def asynTest = Action.async {
val willBeInt = Future {
Thread.sleep(5000)
100
}
// note you will probably need to
// import scala.concurrent.ExecutionContext.Implicits.global
// to be able to call `map` here
willBeInt map { value =>
Ok(s"Value = $value")
} recover {
case e: Throwable => InternalServerError(e.toString)
}
}
For some extra reading, check out the docs for Future, and the docs for Action

In scala how to wrap a PartialFunction?

In scala, Futures have a sort of rescue function that takes a PartialFunction. This code is skipped if the Future resolved with a response but is called if a failure occurs.
I want to simple wrap the partial function in a proxy that always executes code that writes to a stat counter. At first I was thinking I would just create another PartialFunction but soon realized that does not work very well with the isDefined, then apply as I really want this to be called every time.
How do I go about proxying the PartialFunction such that my code is always called when the Future has an exception?
To summarize the comments: You can use the onFailure callback to execute some side-effecting code (logging) when a Future fails.
val future = Future(1 / 0)
future.onFailure {
case _ => println("I have seen the Future, and it doesn't look good.")
}
As #cmbaxter notes, you could also use andThen on the Future, which accepts a PartialFunction[Try[A], B] and returns the original Future. So you could apply the side-effecting function using andThen, and than recover afterwards. You could even chain them multiple times.
Future(1 / 0)
.andThen { case Failure(_) => println("Future failed.") }
.recover { case e: ArithmeticException => 0 }
.andThen { case Failure(_) => println("Tried to recover, and still failed.") }
Or a helper that always includes it:
object FutureLogger {
def apply[A](a: => A): Future[A] = Future(a).andThen {
case Failure(_) => println("FAILURE")
}
}

scala future error for " Don't call `Awaitable` methods directly, use the `Await` object."

My trait method is:
userService{
def link(current: U, to:User): Future[U]
def findUserByEmail(email:String):Future[Option[User]]
}
when I execute I use:
for(link(currentUser, userService.findUserByEmail(email).result(Duration(1000, MILLISECONDS)).get)){
...
}
and the error is:
[error] G:\testprojects\mifun\modules\app\controllers\
ProviderController.scala:130: Don't call `Awaitable` methods directly, use the `
Await` object.
I do not know why here must use await object instead of awaitable methods, and how to change it correctly.
If you want to block you need to use Await.result(userService.findUserByEmail(email), 1000 millis), note that blocking is in general a bad idea as it blocks your main thread waiting for the specified result to return, take a look at onComplete for example.
Something like this:
val futureLink = findUserByEmail(user) flatMap {
maybeUser => maybeUser map (user => link(currentUser, user))
}
futureLink onComplete {
case Success(user:User) => ...
case Success(None) => ...
case Failure(ex) => ...
}
or, if you really need to block, you can do Await.result on futureLink.