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
Related
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)
I have an existing code which returns an instance of certain type.
def myMethod(inputs) = {
.....some calculations
MyInstance(....)
}
I have to make a change in it now. Change calls some service which returns a Future of some value, which I need to use to update MyInstance.
def myMethod(inputs) = {
.....some calculations
val futureWithSomeValue = someexternalservice.getData(....)
futureWithSomeValue.onComplete {
case Success(value) => ....create MyInstance
case Failure => ....throw error
}
}
But onComplete returns Unit, and hence it breaks the code.
What is best way to do it without changing method signature?
If myMethod call a Future then myMethod must return a Future
Thus, as was said in the comments, you may rather use map instead of onComplete to produce a new Future with your instance and return that.
def myMethod(inputs): Future[MyInstance] = {
// some calculations.
val futureWithSomeValue = someexternalservice.getData(....)
futureWithSomeValue.map { value =>
MyInstance(...)
}
I am having problem with my play-framework API server. I need to have some processing running in the background that is returning a Future with the result and then write the result as response. However, the request thread goes all out and return before my Future completes. Here is the code...
def requestAction(): Action[AnyContent] = Action.async { implicit request =>
var fResult: Future[String] = Future { "initial value" }
try {
fResult = doSomethingAsyncAndGetResponseString(); // return "great, everything is done"
}
catch {
case t: Throwable {
fResult = Future { "failed" }
}
}
// done, return response, but the problem is, this is executed first because doSomethingAsyncAndGetResponseString() is still executing and returns later
fResult.map( res => {
// problem here, because I get "initial value" which is not what I want
Ok(res)
}
}
Is there a way to get "great, everything is done" or "failed" without Async.await ? I have been using this format all over in my API server, but today it broke because in a new API that I write, the doSomethingAsyncAndGetResponseString is a bit longer. I didn't expect that, so something must be wrong with how I understand the structure.
Thanks in advance!
You are trying to write Java like code using Scala.
You are doing it wrong. Read about Futures and How to use them.
Here is the tutorial
Futures can be composed using map and flatMap constructs. recover and recoverWith will give the user access to exception happened in the computation pipeline
You have to do something like this, given below
def requestAction(): Action[AnyContent] = Action.async { implicit request =>
Future { "initial value" }.flatMap { _ =>
doSomethingAsyncAndGetResponseString() // returns Future
}.map { res =>
Ok(res)
}.recover { case th =>
Ok(th.getMessage)
}
}
Handling exceptions and recovering from exceptions
Exception handling is inbuilt into Future.
recover gives access to exception and also helps the user to provide the alternative success value in case of exception.
recoverWith gives access to an exception and also helps the user to provide/chain alternative Future computation which can succeed or fail.
Future {
throw new Exception("foo exception")
}.recover {
case th => println(s"msg: ${th.getMessage}")
}
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")
}
}
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.