Scala Play - Action.async with BodyParser - Exception Handling - scala

I am using Scala with Play for my microservice. It has a Controller that uses the Action.async construct with a custom body parser. Here's a sample code:
def crud(param: String) = Action.async(SomeCustomBodyParser) { implicit request =>
try {
<some code>
} catch {
case _ => <Exception Handling logic>
}
}
The issue with this code is that in case of an exception in SomeCustomBodyParser, it does not get handled in the catch block. I tried a few approaches where I extract it outside and then handle it manually, but the exception is not caught correctly. The code of Action.async suggests that it takes a block of code and executes it a separate context. I am unclear exactly how it works.
How can I handle the exception and spit out a better exception message.

The Action.async has to be given a Future[Result], which can be completed either with a successful Result or a failure.
Any failed Future there results in an error HTTP response.
Action.async { Future.failed(new Exception("Foo") }
The way such error is formatted can be cistomized.

The problem here is that you are trying to use synchronous error handler to handle asynchronous error. try catch can only handle synchronous errors. Future[_] is asynchronous by nature and it will, if any, throw error after your try catch statement has already been executed (and possibly in a different thread).
Instead, in scala, we make error handling explicit by using a data structure like Option or Either or \/ from scalaz. All these wrappers form Monad.
In most asynchronous server setting, what you want is Future with Either inside (or right-biased variant like \/ from scalaz.) This way, you abstract over both asynchronity and error handling. Since both wrappers are monads, you can combine them using Monad Transformers. This is a deep topic and requires quite a bit of learning if you are not familiar with it but the gist of such data structure would be something like the following:
class Task[E, A] {
def flatMap[U](f: A => Task[E, U]): Task[E, U] = ??? // Use monad transformer here.
}
where E represents the type of your custom errors - you probably will represent them through algebraic data type like sealed trait with lots of case class and A is your value type.

If your BodyParser throws an exception, or fails for some other reason, then any code inside the Action will not execute. The nature of async is irrelevant here.
For instance, the System.exit in the code below never runs as the BodyParser always returns an exception.
package controllers
import javax.inject.Inject
import play.api.mvc._
import scala.concurrent.Future
class Application #Inject() extends Controller {
def crud(param: String) = Action.async(
parse.error[String](Future.failed(new RuntimeException("oh noes!")))
) { req =>
System.exit(0)
???
}
}
This code generates this stacktrace:
play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception[[RuntimeException: oh noes!]]
at play.api.http.HttpErrorHandlerExceptions$.throwableToUsefulException(HttpErrorHandler.scala:254) ~[play_2.11-2.4.0.jar:2.4.0]
at play.api.http.DefaultHttpErrorHandler.onServerError(HttpErrorHandler.scala:180) ~[play_2.11-2.4.0.jar:2.4.0]
And the stacktrace says there is a DefaultHttpErrorHandler that gets called with exceptions thrown from a BodyParser.
The documentation for ScalaErrorHandling has examples of customising this, or writing your own one.

Related

Mocked methods created within `withObjectMocked` not invoked when called from an `Actor`

I have published a minimal project showcasing my problem at https://github.com/Zwackelmann/mockito-actor-test
In my project I refactored a couple of components from classes to objects in all cases where the class did not really have a meaningful state. Since some of these objects establish connections to external services that need to be mocked, I was happy to see that mockito-scala introduced the withObjectMocked context function, which allows mocking objects within the scope of the function.
This feature worked perfectly for me until I introduced Actors in the mix, which would ignore the mocked functions despite being in the withObjectMocked context.
For an extended explanation what I did check out my github example project from above which is ready to be executed via sbt run.
My goal is to mock the doit function below. It should not be called during tests, so for this demonstration it simply throws a RuntimeException.
object FooService {
def doit(): String = {
// I don't want this to be executed in my tests
throw new RuntimeException(f"executed real impl!!!")
}
}
The FooService.doit function is only called from the FooActor.handleDoit function. This function is called by the FooActor after receiving the Doit message or when invoked directly.
object FooActor {
val outcome: Promise[Try[String]] = Promise[Try[String]]()
case object Doit
def apply(): Behavior[Doit.type] = Behaviors.receiveMessage { _ =>
handleDoit()
Behaviors.same
}
// moved out actual doit behavior so I can compare calling it directly with calling it from the actor
def handleDoit(): Unit = {
try {
// invoke `FooService.doit()` if mock works correctly it should return the "mock result"
// otherwise the `RuntimeException` from the real implementation will be thrown
val res = FooService.doit()
outcome.success(Success(res))
} catch {
case ex: RuntimeException =>
outcome.success(Failure(ex))
}
}
}
To mock Foo.doit I used withObjectMocked as follows. All following code is within this block. To ensure that the block is not left due to asynchronous execution, I Await the result of the FooActor.outcome Promise.
withObjectMocked[FooService.type] {
// mock `FooService.doit()`: The real method throws a `RuntimeException` and should never be called during tests
FooService.doit() returns {
"mock result"
}
// [...]
}
I now have two test setups: The first simply calls FooActor.handleDoit directly
def simpleSetup(): Try[String] = {
FooActor.handleDoit()
val result: Try[String] = Await.result(FooActor.outcome.future, 1.seconds)
result
}
The second setup triggers FooActor.handleDoit via the Actor
def actorSetup(): Try[String] = {
val system: ActorSystem[FooActor.Doit.type] = ActorSystem(FooActor(), "FooSystem")
// trigger actor to call `handleDoit`
system ! FooActor.Doit
// wait for `outcome` future. The 'real' `FooService.doit` impl results in a `Failure`
val result: Try[String] = Await.result(FooActor.outcome.future, 1.seconds)
system.terminate()
result
}
Both setups wait for the outcome promise to finish before exiting the block.
By switching between simpleSetup and actorSetup I can test both behaviors. Since both are executed within the withObjectMocked context, I would expect that both trigger the mocked function. However actorSetup ignores the mocked function and calls the real method.
val result: Try[String] = simpleSetup()
// val result: Try[String] = actorSetup()
result match {
case Success(res) => println(f"finished with result: $res")
case Failure(ex) => println(f"failed with exception: ${ex.getMessage}")
}
// simpleSetup prints: finished with result: mock result
// actorSetup prints: failed with exception: executed real impl!!!
Any suggestions?
withObjectMock relies on the code exercising the mock executing in the same thread as withObjectMock (see Mockito's implementation and see ThreadAwareMockHandler's check of the current thread).
Since actors execute on the threads of the ActorSystem's dispatcher (never in the calling thread), they cannot see such a mock.
You may want to investigate testing your actor using the BehaviorTestKit, which itself effectively uses a mock/stub implementation of the ActorContext and ActorSystem. Rather than spawning an actor, an instance of the BehaviorTestKit encapsulates a behavior and passes it messages which are processed synchronously in the testing thread (via the run and runOne methods). Note that the BehaviorTestKit has some limitations: certain categories of behaviors aren't really testable via the BehaviorTestKit.
More broadly, I'd tend to suggest that mocking in Akka is not worth the effort: if you need pervasive mocks, that's a sign of a poor implementation. ActorRef (especially of the typed variety) is IMO the ultimate mock: encapsulate exactly what needs to be mocked into its own actor with its own protocol and inject that ActorRef into the behavior under test. Then you validate that the behavior under test holds up its end of the protocol correctly. If you want to validate the encapsulation (which should be as simple as possible to the extent that it's obviously correct, but if you want/need to spend effort on getting those coverage numbers up...) you can do the BehaviorTestKit trick as above (and since the only thing the behavior is doing is exercising the mocked functionality, it almost certainly won't be in the category of behaviors which aren't testable with the BehaviorTestKit).

Using Try out of Exception contexts

Is it in Scala acceptable to use Try (Success/Failure) outside of an actual Exception context as a return type of a function that can succeed or fail?
It is certainly possible to use a Try outside an exception context; I use it that way all the time. That does not necessarily mean that it is "acceptable" :)
I would say that the whole point of using Try is to take the Throwable instance out of the exception context and put it in an object that can be used anywhere in a program. It is hard to see why Try would have such a rich set of methods (e.g. flatMap) if it is only intended to be used inside an exception context.
Instances of Try, are either Success or Failure, where Failure is
case class Failure[+T](exception: Throwable)
Note how Failure must be constructed with Throwable, so I think Try is meant to be used within context of Throwables. So we cannot do something like
def foo: Try[Int] = {
Failure(42) // Error: type mismatch; found : Int(42) required: Throwable
}
Consider using Either instead of Try outside exceptions context.
Addressing the comment consider
Valid/Invalid from cats: https://typelevel.org/cats/datatypes/validated.html
define your own ADT with your own meaning of success and failure cases, and then wrap function results in those cases
In neither of these are you forced to use exceptions.
Here is an example
sealed trait MyValidationADT[T]
case class Good[T](result: T) extends MyValidationADT[T]
case class Bad[T](result: T) extends MyValidationADT[T]
def foo(i: Int): MyValidationADT[Int] = Bad(42)
foo(11) match {
case Good(result) => "woohoo"
case Bad(result) => "boom"
}
which outputs
res0: String = boom

Service class and logging design Scala with Futures

I have a service class that gets some data from a database (for context, I'm using Play! Framework). Here's an example method:
def getAccessToken(id: BSONObjectID): Future[Option[String]] = {
userDAO.find(id).map {
case Some(user) =>
user.settings flatMap (_.accessToken)
case _ => None
}
}
I'm trying to improve the error handling (new to Scala) on this thing as there are a couple things that can go wrong:
User might not be found
User might be found but accessToken might not be set (accessToken is an Option[String])
As it stands right now, I can't differentiate between the two. My natural inclination to fix this is to use \/ from Scalaz and have the return type be Future[ErrorType \/ String] and this seems like a reasonable approach. In my controller method, I can for comprehension a bunch of different service methods like this by lifting into a wrapper monad.
But I have the following questions:
Should my ErrorType extend Exception, or should I just use the sealed trait style and just extend from that. I've heard that it is not good practice to use exceptions in Scala, so I'm not sure what the right approach is.
How can I handle logging without polluting the controller class with excessive log statements? If a controller class calls a bunch of these service methods, the controller will have to handle several different ErrorTypes in the for comprehension. Assuming I'm lifting all the monads to a wrapper monad with ?|, I want to avoid this:
accessToken <- service.getAccessToken(id) ?| { error => error match { case Error1 =>
logger.error(
"Unable to find access token for user: " + id
.toString())
InternalServerError(
ApiResponse("internal_server_error",
"Unable to get token."))
case Error2 => ...
}
Thanks!
I think Future[ErrorType / String] is a bit overkill as Future[T] already can hold either an object of type T or an Exception derived one (see Future.successful(...)/ Future.failed(...))
Should my ErrorType extend Exception, or should I just use the sealed trait style and just extend from that. I've heard that it is not good practice to use exceptions in Scala, so I'm not sure what the right approach is.
I would recommend to use a class (or a set of classes, one per particular error type), say YourAppException derived from Exception, as you need to handle low level exceptions one way or another anyway.
I agree that throwing/catching exceptions is not going very well with functional code and it is better to use Try[T] or Future[T] to return errors in a more explicit way instead. On the other hand there is nothing wrong with using an Exception derived class to hold some error info. It is often useful to wrap the original non-application (say IO) exception in an application one and keep a reference to the initial one in Exception's 'cause' for troubleshooting. It gives an opportunity to provide a more context specific error message.
How can I handle logging without polluting the controller class with excessive log statements?
Consider encapsulating error messages in Exception derived case classes, representing application errors so you can access the error messsages uniformly using exception.getMessage. It is easy to add some method to YourAppException to construct ApiResponse as well.
def getAccessToken(id: BSONObjectID): Future[String] = {
userDAO.find(id).flatMap {
case Some(user) =>
val optToken = user.settings.flatMap (_.accessToken)
optToken.map(Future.successful).getOrElse(Future.failed(AccessTokenIsInvalid(user)))
case _ => Future.failed(UserNotFoundError(user))
}
}
case class AccessTokenIsInvalid(user: String)
extends YourAppException(s"Access token is invalid for user $user") {
}
accessToken <- service.getAccessToken(id) ?| { error =>
logger.error(error.getMessage)
InternalServerError(
ApiResponse("internal_server_error", error.getMessage))
}
1) Yes, you are on a right way. The problem with exceptions is that when something fails it's hard to pattern-match on it to detect a reason.
I would do it like that:
sealed trait MyError
object UserNotFound extends MyError
object AuthFailed extends MyError
type MyResult = Either[MyError, String]
2) If a program is well-typed logging is necessary in places where information is lost.
If you deal with, for example, val x = Future[Either[Error, String]], then you haven't throttled potential error yet so logging is optional.
But when you somehow try to extract Either[MyError, String] from it you lose information so you should log it.
The same happens when you extract String from Either[MyError, String].

Exception Passing Through scala.concurrent.Future?

Is it possible for an exception to be thrown, escaping the Future context?
Since a Future "evaluates" as soon as it's defined:
is it possible for the definition of a Future to throw an exception, passing through the Future context?
scala> Future { Thread.sleep(3000); println("3 seconds elapsed"); 100 }
res2: scala.concurrent.Future[Int] =
scala.concurrent.impl.Promise$DefaultPromise#56113384
scala> 3 seconds elapsed
I could not come up with such an example.
scala> Future { throw new Exception("Foo!") }
res3: scala.concurrent.Future[Nothing] =
scala.concurrent.impl.Promise$DefaultPromise#47a86fbb
Yes, but maybe not quite the way you're thinking of. According to the source, only errors that are not NonFatal will escape Future.apply.
try Success(body) catch { case NonFatal(e) => Failure(e) }
i.e. exceptions like: VirtualMachineError, OutOfMemoryError,StackOverflowError, ThreadDeath, LinkageError, InterruptedException, ControlThrowable.. will go uncaught as they represent a fatal JVM error that you will not be able to handle.
A future in itself does nothing except define the computation. It just so happens to be you're using one of the constructors (or apply methods) that, by default, begins running the computation immediately. The mixing of exception handling and concurrency is one of the issues that, unfortunately, not explicit with scala.concurrent.Future. A better alternative may be to use scalaz.concurrent.Task which combines error handling with explicit concurrency.
Why you want to throw an error from your future?
Future is a monad which will handles latency and exceptions while you are dealing with it.
If you look at Future implementation it looks like as below,
trait Future[T] { def onComplete(callback: Try[T] => Unit)(implicit exe..) }
So when as soon as your future gets complete and value available your callback method will be invoked and return unit.
If you see callback method you will get idea your result would be success or error and Try[T] woluld manage all the things for you.

What are the use cases for Scala 2.9's try...catch generalization?

I've read about and experimented with the Scala 2.9 try...catch feature, and it has me thinking about possibilities. What would I actually use it for other than saving a couple of lines of code?
Scala 2.9 Final Release Notes
The use case is to be able to have generic error handling throughout your application. Let's say you want to handle all FileNotFoundExceptions in your application by sending an e-mail to an administrator. Previously, you'd have to do it like this:
// Globally
val fileNotFound: PartialFunction[Throwable, Unit] = {
case e: FileNotFoundException =>
// Create report and send the e-mail
}
// On each try-catch-block
try {
// Open file
}
catch {
case fnf: FileNotFoundException => fileNotFound(fnf)
}
Now you just do:
try {
// Open file
} catch fileNotFound
This also has the nice advantage that you can link several such exception handlers using the orElse method on partial functions:
val fileErrors = fileNotFound orElse endOfFile orElse invalidFormat
And then just use that everywhere where you need file exception handling. Such an error handler can be dynamically combined based on the configuration file for the application, for example. This is much less cumbersome than pattern matching everywhere and calling the correct handler.
One useful thing which could be pimped on top of partial functions is the andAlso operator, which acts as a sequencing operator on two partial functions. This would be useful when you want to do some error handling specific to a particular try-catch block after having done the generic error handling.
implicit def pf2ops(pf: PartialFunction[Throwable, Unit]) = new {
def andAlso(localpf: PartialFunction[Throwable, Unit]) = new PartialFunction[Throwable, Unit] {
def apply(t: Throwable) = {
if (pf.isDefinedAt(t)) pf(t)
localpf(t)
}
def isDefinedAt(t: Throwable) = pf.isDefinedAt(t) || localpf.isDefinedAt(t)
}
}
And then you can do this:
scala> try {
| throw new java.io.FileNotFoundException
| } catch fnf andAlso {
| case e: Exception => println("I don't know, but something is specific to this particular block.")
| }
I don't know, but something is specific to this particular block.
I guess you could play further with the exact semantics and the meaning (and the name) of andAlso.
Good answer by axel22, but I think the real reason for its introduction is something else. The try/catch/finally handling introduced a special case. You used a partial function literal, but you could not actually replace that with a partial function. Now, catch just receive a partial function, and one more special case in the language is gone.