The following Scala code uses cats EitherT to wrap results in a Future[Either[ServiceError, T]]:
package com.example
import com.example.AsyncResult.AsyncResult
import cats.implicits._
import scala.concurrent.ExecutionContext.Implicits.global
class ExternalService {
def doAction(): AsyncResult[Int] = {
AsyncResult.success(2)
}
def doException(): AsyncResult[Int] = {
println("do exception")
throw new NullPointerException("run time exception")
}
}
class ExceptionExample {
private val service = new ExternalService()
def callService(): AsyncResult[Int] = {
println("start callService")
val result = for {
num <- service.doException()
} yield num
result.recoverWith {
case ex: Throwable =>
println("recovered exception")
AsyncResult.success(99)
}
}
}
object ExceptionExample extends App {
private val me = new ExceptionExample()
private val result = me.callService()
result.value.map {
case Right(value) => println(value)
case Left(error) => println(error)
}
}
AsyncResult.scala contains:
package com.example
import cats.data.EitherT
import cats.implicits._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
object AsyncResult {
type AsyncResult[T] = EitherT[Future, ServiceError, T]
def apply[T](fe: => Future[Either[ServiceError, T]]): AsyncResult[T] = EitherT(fe)
def apply[T](either: Either[ServiceError, T]): AsyncResult[T] = EitherT.fromEither[Future](either)
def success[T](res: => T): AsyncResult[T] = EitherT.rightT[Future, ServiceError](res)
def error[T](error: ServiceError): AsyncResult[T] = EitherT.leftT[Future, T](error)
def futureSuccess[T](fres: => Future[T]): AsyncResult[T] = AsyncResult.apply(fres.map(res => Right(res)))
def expectTrue(cond: => Boolean, err: => ServiceError): AsyncResult[Boolean] = EitherT.cond[Future](cond, true, err)
def expectFalse(cond: => Boolean, err: => ServiceError): AsyncResult[Boolean] = EitherT.cond[Future](cond, false, err)
}
ServiceError.scala contains:
package com.example
sealed trait ServiceError {
val detail: String
}
In ExceptionExample, if it call service.doAction() it prints 2 as expected, but if it call service.doException() it throws an exception, but I expected it to print "recovered exception" and "99".
How do I recover from the exception correctly?
That is because doException is throwing exception inline. If you want to use Either, you have to return Future(Left(exception)) rather than throwing it.
I think, you are kinda overthinking this. It does not look like you need Either here ... or cats for that matter.
Why not do something simple, like this:
class ExternalService {
def doAction(): Future[Int] = Future.successful(2)
def doException(): AsyncResult[Int] = {
println("do exception")
Future.failed(NullPointerException("run time exception"))
// alternatively: Future { throw new NullPointerExceptioN() }
}
class ExceptionExample {
private val service = new ExternalService()
def callService(): AsyncResult[Int] = {
println("start callService")
val result = for {
num <- service.doException()
} yield num
// Note: the aboive is equivalent to just
// val result = service.doException
// You can write it as a chain without even needing a variable:
// service.doException.recover { ... }
result.recover { case ex: Throwable =>
println("recovered exception")
Future.successful(99)
}
}
I tend to agree that it seems a bit convoluted, but for the sake of the exercise, I believe there are a couple of things that don't quite click.
The first one is the fact that you are throwing the Exception instead of capturing it as part of the semantics of Future. ie. You should change your method doException from:
def doException(): AsyncResult[Int] = {
println("do exception")
throw new NullPointerException("run time exception")
}
To:
def doException(): AsyncResult[Int] = {
println("do exception")
AsyncResult(Future.failed(new NullPointerException("run time exception")))
}
The second bit that is not quite right, would be the recovery of the Exception. When you call recoverWith on an EitherT, you're defining a partial function from the Left of the EitherT to another EitherT. In your case, that'd be:
ServiceError => AsyncResult[Int]
If what you want is to recover the failed future, I think you'll need to explicitly recover on it. Something like:
AsyncResult {
result.value.recover {
case _: Throwable => {
println("recovered exception")
Right(99)
}
}
}
If you really want to use recoverWith, then you could write this instead:
AsyncResult {
result.value.recoverWith {
case _: Throwable =>
println("recovered exception")
Future.successful(Right(99))
}
}
Related
Scala futures:
With Await.result I can wait for the future to complete before terminating the program.
How can I wait for a Future.onFailure to complete before terminating the program?
package test
import scala.concurrent.duration.Duration
import scala.concurrent.{Await, Future}
import scala.concurrent.ExecutionContext.Implicits.global
object Test5 extends App {
def step(i: Int): Future[String] = Future {
Thread.sleep(1000)
if (i == 3) throw new Exception("exception on t3")
Thread.sleep(1000); val s = s"done: $i"; println(s); s
}
val task: Future[String] = step(1).flatMap(_ => step(2).flatMap(_ => step(3)))
task.onFailure {
case e: Throwable => println("task.onFailure. START: " + e); Thread.sleep(3000); println("task.onFailure. END.")
}
try {
val result: String = Await.result(task, Duration.Inf)
println("RESULT: " + result)
} catch {
case e: Throwable => println("Await.result.try catch: " + e)
}
// without this, "task.onFailure. END." does not get printed.
// How can I replace this line with something such as Await.result([the task.onFailure I set previously])
Thread.sleep(5000)
println("END")
}
Note: Instead of using task.onFailure, I could catch the exception on Await.result (as in the example). But I would prefer to use task.onFailure.
Update
A solution is to use transform or recover as proposed by Ryan. In my case, I needed something more, and I've added this alternative answer: on scala, how to wait for a Future.onFailure to complete?
If all you want to do is to sequence a side-effect such that you know that it has been executed I'd recommend using 'andThen'.
onFailure returns Unit. There's no way to block on that.
Either catch the exception on Await.result or use transform or recover to side-effect on the exception.
You can't. Future#onFailure returns Unit so there is no handle for which you can grab to block execution.
Since you're blocking on the completion of task anyway, the catch clause in your code is equivalent to what you would get from onFailure. That is, if the Future fails, the body of catch will be executed before the program exits because it is running on the main thread (whereas onComplete is not).
We can enrich Future with onComplete2 and onCompleteWith2 as follows:
import scala.concurrent.{ExecutionContext, Future, Promise}
import scala.util.Try
object FutureUtils {
implicit class RichFuture[T](val self: Future[T]) {
def onComplete2[U](f: (Try[T]) => U)(implicit executor: ExecutionContext): Future[T] = {
val p = Promise[T]()
self.onComplete { r: Try[T] => f(r); p.complete(r) }
p.future
}
def onCompleteWith2[U](f: (Try[T]) => Future[U])(implicit executor: ExecutionContext): Future[T] = {
val p = Promise[T]()
self.onComplete { r: Try[T] => f(r).onComplete(_ => p.complete(r)) }
p.future
}
}
}
then I case use it as follows:
import scala.concurrent.duration.Duration
import scala.concurrent.{Await, Future}
import scala.concurrent.ExecutionContext.Implicits.global
import FutureUtils._
import scala.util.{Failure, Success, Try}
object Test5 extends App {
def stepf(i: Int): Future[String] = Future { step(i) }
def step(i: Int): String = {
Thread.sleep(1000)
if (i == 3) throw new Exception("exception on t3")
Thread.sleep(1000); val s = s"done: $i"; println(s); s
}
val task1: Future[String] =
stepf(1).flatMap(_ => stepf(2).flatMap(_ => stepf(3)))
// the result of step(10) and step(11) is ignored
val task2: Future[String] = task1.onComplete2((r: Try[String]) => r match {
case Success(s) => step(10)
case Failure(e) => step(11)
})
/*
// If I want to recover (and so, to avoid an exception on Await.result:
val task3 = task2.recover {case e: Throwable => step(12) }
// I can use onCompleteWith2 instead of onComplete2
val task2: Future[String] = task1.onCompleteWith2((r: Try[String]) => r match {
case Success(s) => stepf(10)
case Failure(e) => stepf(11)
})
*/
try {
val result = Await.result(task2, Duration.Inf)
println("RESULT: " + result)
} catch {
// see my comment above to remove this
case e: Throwable => println("Await.result.try catch: " + e)
}
println("END.")
}
The execution is as follows:
done: 1
done: 2
done: 11
Await.result.try catch: java.lang.Exception: exception on t3
END.
If we don't throw the exception at step(3), the execution is as follows. Note that RESULT is "done: 3", not "done: 10":
done: 1
done: 2
done: 3
done: 10
RESULT: done: 3
END.
Consider this situation, I have a bunch of services that all need to check the input and handle errors.
val log = Logger("access")
def service1(){input=>
try{
val id = input.split(",")(0).toInt
val value = input.split(",")(1)
//do something
} catch {
case e1: NumberFormatException => log.info("number format is wrong")
case e2: ArrayIndexOutOfBoundsException=> log.info("not enough arguments")
}
}
I want to write a method that handles this common part for every service. I could do it this way:
def common(input:String, log:Logger, action:(Int)=>String):String={
try{
val id = input.split(",")(0).toInt
val value = input.split(",")(1)
action(id)
} catch {
case e1: NumberFormatException => log.info("number format is wrong")
case e2: ArrayIndexOutOfBoundsException=> log.info("not enough arguments")
}
}
Then the service function looks like this:
def service1(){input=> common(input, log, id=>{
//do something return a string
})
}
Is there a way to skip the parameters in common so that it looks more elegant like map in collections?
common(id=>{ //... })
import com.typesafe.scalalogging.StrictLogging
class MyService extends AbstractService {
def service1(input: String): String = common(input) {
id =>
id.toString
}
def service2(input: String): String = common(input) {
id =>
id.toString.toLowerCase
}
}
trait AbstractService extends StrictLogging {
def common(input: String)(f: Int => String): String = {
try {
val id = input.split(",")(0).toInt
f(id)
} catch {
case e1: NumberFormatException =>
logger.error("number format is wrong",e1)
"" //???
case e2: ArrayIndexOutOfBoundsException =>
logger.error("not enough arguments",e2)
"" //???
}
}
}
If input is specific you have to put it as input. Otherwise define method def input:String in trait and provide implementation in service.
I want to add an after(d: FiniteDuration)(callback: => Unit) util to Scala Futures that would enable me to do this:
val f = Future(someTask)
f.after(30.seconds) {
println("f has not completed in 30 seconds!")
}
f.after(60.seconds) {
println("f has not completed in 60 seconds!")
}
How can I do this?
Usually I use a thread pool executor and promises:
import scala.concurrent.duration._
import java.util.concurrent.{Executors, ScheduledThreadPoolExecutor}
import scala.concurrent.{Future, Promise}
val f: Future[Int] = ???
val executor = new ScheduledThreadPoolExecutor(2, Executors.defaultThreadFactory(), AbortPolicy)
def withDelay[T](operation: ⇒ T)(by: FiniteDuration): Future[T] = {
val promise = Promise[T]()
executor.schedule(new Runnable {
override def run() = {
promise.complete(Try(operation))
}
}, by.length, by.unit)
promise.future
}
Future.firstCompletedOf(Seq(f, withDelay(println("still going"))(30 seconds)))
Future.firstCompletedOf(Seq(f, withDelay(println("still still going"))(60 seconds)))
One way is to use Future.firstCompletedOf (see this blogpost):
val timeoutFuture = Future { Thread.sleep(500); throw new TimeoutException }
val f = Future.firstCompletedOf(List(f, timeoutFuture))
f.map { case e: TimeoutException => println("f has not completed in 0.5 seconds!") }
where TimeoutException is some exception or type.
Use import akka.pattern.after. If you want to implement it without akka here is the source code. The other (java) example is TimeoutFuture in com.google.common.util.concurrent.
Something like this, perhaps:
object PimpMyFuture {
implicit class PimpedFuture[T](val f: Future[T]) extends AnyVal {
def after(delay: FiniteDuration)(callback: => Unit): Future[T] = {
Future {
blocking { Await.ready(f, delay) }
} recover { case _: TimeoutException => callback }
f
}
}
}
import PimpMyFuture._
Future { Thread.sleep(10000); println ("Done") }
.after(5.seconds) { println("Still going") }
This implementation is simple, but it basically doubles the number of threads you need - each active future effectively occupies two threads - which is a bit wasteful. Alternatively, you could use scheduled tasks to make your waits non-blocking. I don't know of a "standard" scheduler in scala (each lib has their own), but for a simple task like this you can use java's TimerTask directly:
object PimpMyFutureNonBlocking {
val timer = new java.util.Timer
implicit class PimpedFuture[T](val f: Future[T]) extends AnyVal {
def after(delay: FiniteDuration)(callback: => Unit): Future[T] = {
val task = new java.util.TimerTask {
def run() { if(!f.isCompleted) callback }
}
timer.schedule(task, delay.toMillis)
f.onComplete { _ => task.cancel }
f
}
}
}
Following code when written using generic give a compilation error.
Without Generic
def getData(id: String) = Action.async {
val items = getItems(id)
sendResult(items)
}
private def sendResult(result: Future[Any]) = {
result.map {
items => {
try {
val itemStr = items.asInstanceOf[String]
Ok(itemStr)
} catch {
case t: ClassCastException => InternalServerError(s"Casting Exception while processing output $t")
}
}
}.recover {
case t:TimeoutException => InternalServerError("Api Timed out")
case t: Throwable => InternalServerError(s"Exception in the api $t")
}
}
With Generic
def getData(id: String) = Action.async {
val items = getItems(id)
sendResult[String](items)
}
private def sendResult[T](result: Future[Any]) = {
result.map {
items => {
try {
val itemStr = items.asInstanceOf[T]
Ok(itemStr)
} catch {
case t: ClassCastException => InternalServerError(s"Casting Exception while processing output $t")
}
}
}.recover {
case t:TimeoutException => InternalServerError("Api Timed out")
case t: Throwable => InternalServerError(s"Exception in the api $t")
}
}
The code is part of play app's contorller method. First one works fine. Second one gives following compilation error
Cannot write an instance of T to HTTP response. Try to define a
Writeable[T] [error] Ok(itemStr) [error]
Using Any with a generic function doesn't make much sense.
private def sendResult[T](result: Future[Any])
// Should better be
private def sendResult[T](result: Future[T])
// ... also remove the unsafe cast
Then this T needs to be provided an instance of Writeable, so it can be written a Array[Byte] over network.
// Either ...
private def sendResult[T: Writeable](result: Future[T])
// ... or ...
private def sendResult[T](result: Future[T])(implicit w: Writeable[T])
The Ok(...) is calling the method apply[C](content: C)(implicit writeable: Writeable[C]): Result on Status class. You need to have an implicit value for Writeable[T] in scope.
As a side note, rather than using Future[Any], you may as well use Future[T] and remove the cast. Also you can use Writes for JSON serialization.
private def sendResult[T](result: Future[T])(implicit writeable: Writes[T]) = {
result.map {
items => {
Ok(Json.toJson(items))
}
}.recover {
case t:TimeoutException => InternalServerError("Api Timed out")
case t: Throwable => InternalServerError(s"Exception in the api $t")
}
}
Here is the problem, I have a library which has a blocking method return Try[T]. But since it's a blocking one, I would like to make it non-blocking using Future[T]. In the future block, I also would like to compute something that's depend on the origin blocking method's return value.
But if I use something like below, then my nonBlocking will return Future[Try[T]] which is less convince since Future[T] could represent Failure[U] already, I would rather prefer propagate the exception to Future[T] is self.
def blockMethod(x: Int): Try[Int] = Try {
// Some long operation to get an Int from network or IO
throw new Exception("Network Exception") }
}
def nonBlocking(x: Int): Future[Try[Int]] = future {
blockMethod(x).map(_ * 2)
}
Here is what I tried, I just use .get method in future {} block, but I'm not sure if this is the best way to do that.
def blockMethod(x: Int): Try[Int] = Try {
// Some long operation to get an Int from network or IO
throw new Exception("Network Exception") }
}
def nonBlocking(x: Int): Future[Int] = future {
blockMethod(x).get * 2
}
Is this correct way to do that? Or there is a more scala idiomatic way to convert t Try[T] to Future[T]?
Here's an example that doesn't block, note that you probably want to use your own execution context and not scala's global context:
import scala.util._
import scala.concurrent._
import scala.concurrent.duration._
import ExecutionContext.Implicits.global
object Main extends App {
def blockMethod(x: Int): Try[Int] = Try {
// Some long operation to get an Int from network or IO
Thread.sleep(10000)
100
}
def tryToFuture[A](t: => Try[A]): Future[A] = {
future {
t
}.flatMap {
case Success(s) => Future.successful(s)
case Failure(fail) => Future.failed(fail)
}
}
// Initiate long operation
val f = tryToFuture(blockMethod(1))
println("Waiting... 10 seconds to complete")
// Should return before 20 seconds...
val res = Await.result(f, 20 seconds)
println(res) // prints 100
}
In my opinion: Try & Future is a monadic construction and idiomatic way to is monadic composition (for-comprehension):
That you need to define monad transformer for Future[Try[_]] (code for your library):
case class FutureT[R](run : Future[Try[R]])(implicit e: ExecutionContext) {
def map[B](f : R => B): FutureT[B] = FutureT(run map { _ map f })
def flatMap[B](f : R => FutureT[B]): FutureT[B] = {
val p = Promise[Try[B]]()
run onComplete {
case Failure(e) => p failure e
case Success(Failure(e)) => p failure e
case Success(Success(v)) => f(v).run onComplete {
case Failure(e) => p failure e
case Success(s) => p success s
}
}
FutureT(p.future)
}
}
object FutureT {
def futureTry[R](run : => Try[R])(implicit e: ExecutionContext) =
new FutureT(future { run })
implicit def toFutureT[R](run : Future[Try[R]]) = FutureT(run)
implicit def fromFutureT[R](futureT : FutureT[R]) = futureT.run
}
and usage example:
def blockMethod(x: Int): Try[Int] = Try {
Thread.sleep(5000)
if(x < 10) throw new IllegalArgumentException
else x + 1
}
import FutureT._
// idiomatic way :)
val async = for {
x <- futureTry { blockMethod(15) }
y <- futureTry { blockMethod(25) }
} yield (x + y) * 2 // possible due to using modan transformer
println("Waiting... 10 seconds to complete")
val res = Await.result(async, 20 seconds)
println(res)
// example with Exception
val asyncWithError = for {
x <- futureTry { blockMethod(5) }
y <- futureTry { blockMethod(25) }
} yield (x + y) * 2 // possible due to using modan transformer
// Can't use Await because will get exception
// when extract value from FutureT(Failure(java.lang.IllegalArgumentException))
// no difference between Failure produced by Future or Try
asyncWithError onComplete {
case Failure(e) => println(s"Got exception: $e.msg")
case Success(res) => println(res)
}
// Output:
// Got exception: java.lang.IllegalArgumentException.msg