Akka http outGoingConnection is stuck - scala

Calling the below httpConnection is neither returning Flow[HttpRequest, HttpResponse, Future[Http.OutgoingConnection]] nor going into catch block.
It's just stuck.
lazy val httpConnection= Try{
logger("Logger statement")
http().outgoingConnection(host,port)
}
catch {
case e:Exception: /***Action***/
}
httpConnection match {
case f: Flow[HttpRequest, HttpResponse,Future[Http.OutgoingConnection]] => Source.single(request).via(flow).runWith(Sink.head)
case e: Exception => logger("not able to get connection")
}

Related

Propagate errors through a chain of Scala futures

Considering a sequence of futures each returning Either[Status, Resp].
How would you propagate error status codes through a for comprehension which is using Future and not Either?
The code bellow does not work, since the parsing exception is not caught by .recover of the last future
The use case is Scala Play ActionRefiners which returns Future[Either[Status, TRequest[A]]].
def parseId(id: String):Future[Int] = {
Future.successful(Integer.parseInt(id))
}
def getItem(id: Int)(implicit ec: ExecutionContext): Future[Either[Status, String]] =
Future(Some("dummy res from db " + id)).transformWith {
case Success(opt) => opt match {
case Some(item) => Future.successful(Right(item))
case _ => Future.successful(Left(NotFound))
}
case Failure(_) => Future.successful(Left(InternalServerError))
}
(for {
id <- parseId("bad request")
resp <- getItem(id)
} yield resp).recover {
case _:NumberFormatException => Left(BadRequest)
}
I could move the .recover to parseId, but this makes the for comprehension very ugly - having to treat the Either[Status, id] in the middle
def parseId(id: String):Future[Either[Status, Int]] = {
Future.successful(Right(Integer.parseInt(id))).recover {
case _:NumberFormatException => Left(BadRequest)
}
}
Your exception is not caught because you are not throwing it inside the Future: Future.successful is immediately satisfied with the result of the expression you give it, if it throws an exception, it is executed on the current thread.
Try removing the .successful: Future(id.toInt) will do what you want.
Also, I would recommend to get rid of all the Eithers: these are highly overrated/overused, especially in the context of Future (that already wrap their result into Try anyhow), and just make the code more complicated and less readable without offering much benefit.
case class FailureReason(status: Status)
extends Exception(status.toString)
def notFound() = throw FailureReason(NotFound)
def internalError() = throw FailureReason(InternalError)
def badRequest() = throw FailureReason(BadRequest)
def parseId(id: String):Future[Int] = Future(id.toInt)
def getItem(id: Int): Future[String] = Future(Some("dummy"))
.map { _.getOrElse(notFound) }
.recover { _ => internalError }
// this is the same as your for-comprehension, just looking less ugly imo :)
parseId("foo").flatMap(getItem).recover {
case _: NumberFormatException => badRequest()
}
// if you still want `Either` in the end for some reason:
.map(Right.apply[Status, String])
.recover {
case _: NumberFormatException => Left(BadRequest) // no need for the first recover above if you do this
case FailureReason(status) => Left(status)
}

Unit test always returns scala match error null or null pointer exception

Currently trying to test authentication controller using specs2 and scalatest, my application runs fine, but the test always return NullPointerException or Scala Match error null
val userRepository: UserRepository = mock[UserRepository]
val userService: UserService = mock[UserService]
val authenticator: Authenticator = mock[Authenticator]
val authenticationService: AuthenticationService = mock[AuthenticationService]
implicit val ec = mock[ExecutionContext]
implicit val materializer = mock[Materializer]
val authenticationController = new AuthenticationController(Helpers.stubControllerComponents(
playBodyParsers = Helpers.stubPlayBodyParsers(materializer)
), authenticationService, authenticator, userService)
"User" should "login successfully" in {
val request = FakeRequest(POST, "/api/login").withHeaders(CONTENT_TYPE -> "application/json")
.withBody[JsValue](Json.parse("""{"email": "nghia_hd#flinters.vn", "password": "a12306789H#"}"""))
val result: Future[Result] = authenticationController.login().apply(request)
result.map {data => data.header.status shouldBe OK}
}
}
When using Intellij debugger, the exception seems to be here, but I dont really understand how to fix it
def login: Action[JsValue] = Action(parse.json) {
implicit request =>
UserLoginForm.form.bindFromRequest.fold(
formWithErrors => badRequestWarning(formWithErrors.errors),
user => {
--> authenticationService.verify(user) match {
case Success(result) => success(UserPayload.encode(result))
case Failure(exception) => exception match {
case _: PasswordNotMatch => error(Unauthorized, 401, "Password not match")
case _: EntityNotFoundException => error(Unauthorized, 400, "Email not found")
case _ => error(InternalServerError, 500, "An error occurred")
}
}
}
)
}
I've not used specs2/scalatest specifically, but usually you need to specify the response of the mocked method. You need to add this to the test:
when(authenticationService.verify(any())).thenReturn(someMockUser)
Otherwise (depending on your test settings) it will return null. There's also testing frameworks where you can instead throw an exception if methods that aren't mocked are called on mock objects.

scala exception handling with series of dependent future and non-future method calls

I have a method that may return Future - successful or failed or can even throw an exception. I can avoid this by putting try catch block on entire method and return Future all the time but i would like to avoid it for now. I have few problems with calling such method:
1) In caller code, if I use map I expect execution of a method and expect a Future or an exception which I tried to handle in following manner:
object ETLCoordinator {
private def getBusinessListFromModules(modulePaths: Iterable[File]) : Future[String] = {
implicit val ec = ExecutionContext.global
println("Inside getBusinessListFromModules..")
throw new java.lang.RuntimeException("failed to get businesses") //Exception is thrown before future was constructed
Future("ok")
}
def main(args: Array[String]) {
println("Inside Future Test..")
implicit val ec = ExecutionContext.global
val modulePaths = Iterable(new File("mdrqaint/MDR/QAINT/QAINTX"))
val fut1 = getBusinessListFromModules(modulePaths) //This is outside of try and which should be okay
try {
fut1.map { res =>
println("things after Successful fut1")
}.recover{
case t: Throwable => println("Failed future in fut1: "+ t.getMessage)
}
} catch {
case t: Throwable => println("Exception in fut1: "+ t.getMessage)
}
}
}
Output: ( No execution of recover or catch block above)
Inside Future Test..
Inside getBusinessListFromModules..
Exception in thread "main" java.lang.RuntimeException: failed to get businesses
But if I put val fut1 = getBusinessListFromModules(modulePaths) inside Try block then Exception is get caught in Catch block and I get output:
Inside Future Test..
Inside getBusinessListFromModules..
Exception in fut1: failed to get businesses
Why is this? I though Future execution happens upon calling some of its methods like map, flatmap, onSuccess, onComplete etc. In this case call to map is already inside Try block.
2) What is the better way to define and call such methods? Try/catch block in a caller or try/catch in method itself? or any other way. I tried wrapping the calling method in Future so I get Future[Future[String]] in caller. I was able to avoid all try-catch.
val fut1 = Future(getBusinessListFromModules(modulePaths))
//try {
fut1.map { res =>
res.map{ str =>
println("things after Successful fut1")
}.recover{
case t: Throwable => println("Failed in future of fut1: "+ t.getMessage)
}
println("things after Successful fut1 wrapper")
}.recover{
case t: Throwable => println("Failed to create future in fut1: "+ t.getMessage)
}
3) If there is another method inbetween which does delegation to getBusinessListFromModules but it itself is non-future method.
object ETLController {
private def getBusinessListFromModules(modulePaths: Iterable[File]) : Future[String] = {
implicit val ec = ExecutionContext.global
println("Inside getBusinessListFromModules..")
//throw new java.lang.RuntimeException("failed to get businesses")
Future("ok")
}
private def callGetBusList(modulePaths: Iterable[File]) : String = {
implicit val ec = ExecutionContext.global
val etlF = getBusinessListFromModules(modulePaths)
etlF onComplete {
case Success(itr) => {
println("Future getBusinessListFromModules success: "+ itr)
throw new java.lang.RuntimeException("RTE from callGetBusList")
}
case Failure(t) => {
println("Future getBusinessListFromModules throws an error")
}
}
"callGetBusList was a success"
}
def main(args: Array[String]) {
println("Inside Future Test..")
implicit val ec = ExecutionContext.global
val modulePaths = Iterable(new File("mdrqaint/MDR/QAINT/QAINTX"))
try {
val fut = Future(callGetBusList(modulePaths))
fut.map { res =>
println("successful future!")
}.recover{
case t: Throwable => println("Failed future: "+ t.getMessage)
}
} catch {
case t: Throwable => println("callGetBusList failed:" + t.getMessage)
}
}
}
Output: (no recover or catch block execution!)
Inside Future Test..
Inside getBusinessListFromModules..
Future getBusinessListFromModules success: ok
java.lang.RuntimeException: RTE from callGetBusList
at ..
successful future!
I even try double wrapping Future calls :
val fut = Future(Future(callGetBusList(modulePaths)))
fut.map { res =>
res.map { str =>
println("successful inner future! "+ str)
}.recover{
case t: Throwable => println("Failed inner future: "+ t.getMessage)
}
println("successful outer future!")
}.recover{
case t: Throwable => println("Failed outer future: "+ t.getMessage)
}
Output:
Future getBusinessListFromModules success: ok
java.lang.RuntimeException: RTE from callGetBusList
at
successful inner future! callGetBusList was a success
successful outer future!
I get "callGetBusList was a success" which seems like RuntimeException inside onComplete method got lost! How do I catch it in a final caller? What are the better practice to handle such future dependencies?
UPDATE:
based on #dk14 explanation, Opted to convert middle method to return Future and basically all methods to return some kind of Future and not a plain Exception.
object ETLController {
private def getBusinessListFromModules(modulePaths: Iterable[File]) : Future[String] = {
implicit val ec = ExecutionContext.global
println("Inside getBusinessListFromModules..")
Future {
Thread.sleep(2000)
throw new java.lang.RuntimeException("failed to get businesses")
"ok"
}
}
private def callGetBusList(modulePaths: Iterable[File]) : Future[String] = {
implicit val ec = ExecutionContext.global
val etlF = getBusinessListFromModules(modulePaths)
etlF map { itr =>
println("Future getBusinessListFromModules success: "+ itr)
throw new java.lang.RuntimeException("RTE from callGetBusList")
} recover {
case t: Throwable => {
println("Future callGetBusList throws an error: " + t.getMessage)
throw t
}
}
}
def main(args: Array[String]) {
println("Inside Future Test..")
implicit val ec = ExecutionContext.global
val modulePaths = Iterable(new File("mdrqaint/MDR/QAINT/QAINTX"))
val fut = callGetBusList(modulePaths)
fut.map { str =>
println("successful future! "+ str)
}.recover{
case t: Throwable => println("Failed future: "+ t.getMessage)
}
println("Active threads: " +Thread.activeCount())
sys.allThreads().foreach(t => t.join())
}
}
1) Futures are firing eagerly and they aren't referentially transparent.
Answers to the referenced question also contain some insights about Future's internal behavior, so I'd like to skip it here.
In order to manage side-effects concerning execution pools/queues/threads in a more predictable way, you could consider scalaz/monix/fs2 Task or iteratee/scalaz/cats Eval (more abstract lazy evaluation, and intended for sync stuff) + Cont (continuations are abstracting over subscriptions) as alternative. All are referentially transparent and start execution lazily "on-demand".
2) The best way is the one you don't like: to not throw exception outisde of Future context.
You might also consider flatMap to avoid Future[Future[T]]
3) Double wrapping Futures directly a-la Future(Future(...)) doesn't change anything. Your method is executed on val etlF = g... (in the same thread) no matter what it returns. Future("ok")'s content (lambda) is executed eagerly (with "small" unpredictable delay) on a different thread but [execution task is being submitted to the pool] still inside getBusinessListFromModules.
One workaround (not really recommended) is val etlF = Future(getBusinessListFromModules(...)).flatMap(identity) which would return you a future wrapping any exception coming directly from getBusinessListFromModules and indirectly from getBusinessListFromModules's internal Future.
It's better to refactor getBusinessListFromModules itself however, also introduce different exception types for different kinds of trouble (validation, sync vs async, so on) your method might get into.
P.S. There are ways to mix async and sync exception handling, but in practice it's hard to analyze and predict such mixed behavior (which you probably noticed already). And code gets ugly.

Catch exception in Play 2 Test + Futures

how do I catch an exception inside a future success using play to test?
Here is my code:
"A Validity" should {
"be created based on Client's Mobile" in new WithApplication {
val objectId = UUIDs.timeBased()
CValidityServiceModule.checkValidity(true, "MOBILE", clientId, objectId)
val future = genericService.findByObjectIdAndByClientId(objectId, clientId)
future.onComplete {
case Success(s) => {
s match {
case Some(v) => {
v.clientId mustEqual clientId
v.objectId mustEqual objectId
}
case None => assert(false)
}
}
case Failure(t) => {
assert(false, t.getMessage)
}
}
}
Basically if any matcher fail, it trows me an exception, but the test is green.
Any idea?
You need to wait for the Future to complete before testing it. Using the onComplete callback won't work because the test completes before the Future, and the exception is thrown in a different context.
Await.result should do it for you:
import scala.concurrent.Await
import scala.concurrent.duration.Duration
val future = genericService.findByObjectIdAndByClientId(objectId, clientId)
val s = Await.result(future, Duration.Inf)
s match {
case Some(v) => {
v.clientId mustEqual clientId
v.objectId mustEqual objectId
}
case None => assert(false)
}

Why are all HttpResponse's sent to dead letters (it worked fine so far)?

This morning my code just stopped working. All the HttpResponses are now sent incorrectly to deadLetter. What could be the issue?
class MyActor extends Actor {
val mediator = DistributedPubSubExtension(context.system).mediator
def receive = {
case "tick" => {
val pipeline = sendReceive ~> unmarshal[MyItems[Id]]
val pipeline2: HttpRequest => Future[HttpResponse] = sendReceive
val responseFuture: Future[MyItems[Id]] = pipeline(Get(path))
responseFuture onComplete {
case Success(json_items: MyItems[Id]) =>
mediator.tell(DistributedPubSubMediator.Publish("I have response", ResponseTime(format.format(Calendar.getInstance().getTime())), self)
case Failure(t) => println("An error has occured: " + t.getMessage)
}
}
}
}
The problem was that server was sending different messages and they were not parsable to MyItems object, so it caused error and the server response was forwarded to deadletters.