Can't seem to get Future to run callback in Scala - scala

(I've not included the imports so as not to clutter this question)
(This is the simplest possible Scala App (created using scala-minimal template on Typesafe Activator))
I'm trying to run a query against an Elasticsearch Server.
I've run the same code on sbt console and I can see the results alright.
However, when I run the following code, I see "END" (code after the callbacks) being printed, but neither the Success callback nor the Failure callback get run.
I'm a Scala noob, so maybe I'm doing something wrong here? This code compiles. (Just to let you know all the imports are there)
object Hello{
def main(args: Array[String]): Unit = {
val client = ElasticClient.remote("vm-3bsa", 9300)
val res:Future[SearchResponse] = client.execute{ search in "vulnerabilities/3bsa" query "css" }
res onComplete{
case Success(s) => println(s)
case Failure(t) => println("An error has occured: " + t)
}
println("END")
//EDIT start
Await.result(res,10.seconds)
//EDIT end
}
}
FINAL EDIT
Instead of using onComplete, it works if I, instead, print result of the call to Await.result:
val await=Await.result(res,10.seconds)
println(await)
// results shown

The main thread will register your onComplete, println("END") and then exit, this makes the program terminate so therefore you never see your onComplete callback.
You can use Await.result(future, timeout) to block the main thread to keep it alive until the answer arrives. In a server context that would be a big no-no but in a small app like this it is not a problem blocking one thread.

Related

Scala App doesn't exit even though Future is completed

I wait for a Future to complete and print the content on the console. Even when everything is finished, the main application doesn't exit and I have to kill it manually.
def main(args: Array[String]): Unit {
val req = HttpRequest(GET, myURL)
val res = Http().singleRequest(req)
val resultsFutures = Future {
val resultString = Await.result(HttpRequests.unpackResponse(res), Duration.Inf)
JsonMethods.parse(resultString).extract[List[Results]]
}
val results = Await.result(resultsFutures, Duration.Inf)
println(results)
}
So results gets printed on the console with the expected contend, but the application still doesn't end.
Is there something I can do to exit the application? Is there still something running, that the main is waiting for?
I'm using:
scala 2.12.10
akka 2.5.26
akkaHttp 10.1.11
As you are using Akka, you likely have an ActorSystem instantiated somehow under the hood that will keep the process running.
Either you are able to get a hand on it and call its actorSystem.terminate() method, or you can also use an explicit sys.exit(0) at the end of your main method (0 being the exit code you want).
Edit: you should also wrap the Awaits in Try and make sure to call sys.exit in case of failures as well.

Using race from cats-effect prevents app from exiting

I've got simple cats-effect app, which download site from the URL given as argument. During downloading app is supposed to display "loading bar" by writting dots (.) to console. I implemented it by doing race of two IOs one for downloading another for displaying dots.
This is whole app on scastie.
The most important part is here:
def loader(): IO[Unit] = for {
_ <- console.putStr(".")
_ <- timer.sleep(Duration(50, MILLISECONDS)) *> loader()
} yield {}
def download(url: String): IO[String] = IO.delay(Source.fromURL(url)).map(_.mkString)
def run(args: List[String]): IO[Unit] = {
args.headOption match {
case Some(url) =>
for {
content <- IO.race(download(url), loader()).map(_.left.get)
_ <- console.putStrLn() *> console.putStrLn(s"Downloaded site from $url. Size of downloaded content is ${content.length}.")
} yield {}
case None => console.putStrLn("Pass url as argument.")
}
}
Everything works as I expected, when I run it, I get:
..............
Downloaded site from https://www.scala-lang.org. Size of downloaded content is 47738.
Only problem is that app never exits.
As far as I checked loader IO gets cancelled correctly. I can even add something like this:
urlLoader.run(args) *> console.putStrLn("???") *> IO(ExitCode.Success)
And ??? gets displayed.
Also when I remove race, then app exits correctly.
So my question how can I fix this and make my app exit at the end?
To follow up on my comment above: the problem is that your ScheduledExecutorService has threads running that prevent the JVM from exiting, even though your timer's tasks have been cancelled. There are several ways you could resolve this:
Add a IO(ses.shutdown()) before IO(ExitCode.Success).
Call newScheduledThreadPool with a thread factory that daemonizes its threads.
Use the timer: Timer that you get for free inside IOApp.
The last of these is almost definitely the right choice—using the timer (and ContextShift) provided by IOApp will give you reasonable defaults for this and other behaviors.
You may also prevent an early JVM exit using Scala futures with a code like this:
import scala.concurrent.{Await, Future}
import scala.concurrent.duration.Duration
Await.ready(Future.never, Duration.Inf)

Unpacking Future[Option[MyType]] in Scala

I am new to Scala and Play Framework so I am not quite sure what is wrong. I am trying to unpack a Future[Option[MyType]] given by a Slick DB controler (Play Framework). MyType is called BoundingBox in the code:
def getBoundingBoxByFileName(name: String) = {
val selectByName = boundingBoxTableQuery.filter{ boundingBoxTable =>
boundingBoxTable.name === name
}
db.run(selectByName.result.headOption)
}
BoundingBox type has a field called product_name. To retrieve this field I do the following:
val boundingBoxFutOpt = BoundingBoxQueryActions.getBoundingBoxByFileName("some_file")
val res = for {
optBb : Option[db.BoundingBox] <- boundingBoxFutOpt
} yield{
for(bb : db.BoundingBox <- optBb) yield {
println(s"${bb.product_name}")
}
}
This code does not yield anything on the output, though I have no compilation errors. If I change the println statement for some random text (not using the bb reference), it is also not printed on the console. To me it seems that the println statement is never executed.
I'll appreciate some directions on this problem.
It's likely that your program is terminating before the future has a chance to run the println. I think this will get you what you want:
import scala.concurrent.Await
import scala.concurrent.duration.Duration
// your code here
Await.result(res, Duration.Inf)
In your above example you're running a thread but then not giving it a chance to finish execution. The above will block until the future is complete.
It's worth nothing that you shouldn't use Await in production code as the blocking done negates the value of having code run in a separate thread.

scala Futures: possible to find out if an 'onFailure' callback has been installed (so we can implement default error handling)?

My question is somewhat related to this question about default error handlers for Scala futures.
The twist is, I want to install a default error handler that only kicks in if no onFailure (or onComplete)
callback has been installed on the Future. I think this would be quite useful because i have
written code where my Futures fail silently leaving me confused about what's going on.
A fallback error handler would enable me to easily identify errant Futures for which an
appropriate onFailure callback was never defined.
Below is a code sample which illustrates where this could be useful.
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent._
import scala.language.implicitConversions
import scala.language.postfixOps
def futureWithLogging[T](fut: Future[T]) =
fut.transform(identity, { t: Throwable =>
Console.err.println(s"failed with $t")
t
})
{
val f = futureWithLogging ( Future {
Thread.sleep(1000)
throw new scala.RuntimeException("")
} )
f.onFailure{ case err:Throwable => {println("custom error message"); err.printStackTrace()} }
println(s"future value is: ${f.value}")
Thread.sleep(1000)
println(s"future value is now: ${f.value}")
Thread.sleep(1000)
}
Notice that I have a
futureWithLogging function which installs some default error handling behavior on any future that
you pass into the function. Now, if I forget to install an onFailure on a future this is very handy.
But in the code above you see that I have an onFailure handler is installed on Future 'f'.
The result is that I get noise in my log. I see two error messages:
failed with <exception>
and
custom error message...
Where in this case I only want to see the second one
Any guidance you could provide is much appreciated !
The nearest I have come to what you want, is for any specific failure handler to wrap the exception in a special "HandledException" wrapper, that the default failure handler can deal with specially (ignore, or print a suitable message, or whatever). Eg:
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent._
import scala.language.implicitConversions
import scala.language.postfixOps
case class HandledException(inner: Throwable) extends RuntimeException(inner)
def futureWithLogging[T](fut: Future[T]) =
fut.transform(identity, { t: Throwable =>
Console.err.println(s"failed with $t")
HandledException(t)
})
{
val f = futureWithLogging ( Future {
Thread.sleep(1000)
throw new scala.RuntimeException("")
} )
f.onFailure {
case HandledException(inner) => println("Already handled: "+inner)
case err:Throwable => {println("custom error message"); err.printStackTrace()}
}
println(s"future value is: ${f.value}")
Thread.sleep(1000)
println(s"future value is now: ${f.value}")
Thread.sleep(1000)
}
From here, you could add, say, an issue ID to the "HandledException" class, which can be printed out where the initial exception is first caught, then passed up to the front end (and possibly printed out short-hand on the way by things like the default handler) and presented to the user with a message like "Sorry, we hit an error - you can email our support crew, quoting issue ID '...' for help" or whatever you like. This ID could be stored in a DB, traced through log files (maybe put into the logging framework's diagnostic context, if appropriate), etc.

JVM Perm Gen / System freeze after capturing a function which is generated in an interpreter run

I am using Scala dynamically embedded, and I thought I was smart to save re-interpretation of bits by capturing them in a Function0 of the host program. Approximately like this:
object Code
def intp: IMain = ???
object Capture {
private val vr = new ThreadLocal[() => Any]
def apply[A](thunk: => A) {
vr.set(() => thunk)
}
def result: () => Any = vr.get()
}
def capture(code: String): Future[() => Any] = future {
blocking {
intp.setExecutionWrapper("Code.Capture")
intp.interpret(code)
Capture.result
}
}
}
This "somehow" works, but soon after the JVM goes nuts, basically hangs, produces Perm Gen errors etc. So I must be doing something forbidden. If I do not use the capture mechanism, it all runs smoothly (but I have to re-execute the interpret method over and over again instead of keeping the compiled function), so there is nothing wrong on that end.
I tried to run through a step debugger to see if I find anything suspicious, but no. At some point the program just completely freezes. I also isolated the futures case by launching a separate thread for the compilation with an auxiliary Promise on the main capture block that waits for is completion, that didn't change anything.
Any help is appreciated. Perhaps there is a confusion with class loaders and such? (my IMain does override parentClassLoader to be able to access the host classes).
I had a final intuition that perhaps I should serialize the function in the apply method (writeObject), and then deserialise in the host. But the readObject then produces a
java.lang.ClassNotFoundException: $line1.$read$$iw$$iw$$anonfun$1
Hinting perhaps at the problem beneath?