If a Scala future fails, and there is no continuation that "observes" that failure (or the only continuations use map/flatMap and don't run in case of failure), then errors go undetected. I would like such errors to be at least logged, so I can find bugs.
I use the term "observed error" because in .Net Tasks there is the chance to catch "unobserved task exceptions", when the Task object is collected by the GC. Similarly, with synchronous methods, uncaught exceptions that terminate the thread can be logged.
In Scala futures, to 'observe' a failure would mean that some continuation or other code reads the Exception stored in the future value before that future is disposed. I'm aware that finalization is not deterministic or reliable, and presumably that's why it's not used to catch unhandled errors, although .Net does succeed in doing this.
Is there a way to achieve this in Scala? If not, how should I organize my code to prevent unhandled error bugs?
Today I have andThen checkResult appended to various futures. But it's hard to know when to use this and when not to: if a library method returns a Future, it shouldn't checkResult and log errors itself, because the library user may handle the failure, so the responsibility falls onto the user. As I edit code I sometimes need to add checks and sometimes to remove them, and such manual management is surely wrong.
I have concluded there is no way to generically notice unhandled errors in Scala futures.
You can just use Future.recover in the function that returns the Future.
So for instance, you could just "log" the error and rethrow the original exception, in the simplest case:
def libraryFunction(): Future[Int] = {
val f = ...
f.recover {
case NonFatal(t) =>
println("Error : " + t)
throw t
}
}
Note the use of NonFatal to match all the exception types it is sensible to catch.
That recover block could equally return an alternative result if you wish.
Related
For example:
An unguarded throw of type {0} was detected. Refactor this code to either throw an exception of type InvalidPluginExecutionException or guard against thrown exceptions of other types.
What could the first 'throw' mean? Is it a synonym for 'show' or 'return'?
Most languages allow the "throwing" of exceptions. If a function throws an exception, it means that under certain logic paths it chooses not to gracefully handle an problem and passes it on to the user to handle.
In your case, it would seem:
you are using a typed language
the compiler knows which functions throw exceptions
the compiler does not allow / warns against unhandled (unguarded) exceptions
You are likely using a function that can throw an exception under certain cases and your code does not "catch" (handle) that exception, leading to certain cases in which your code is implicitly throwing an exception despite you not explicitly writing any exception throwing code. The compiler is telling you to handle the implicit case by handling the exception (in most languages this is accomplished with some sort of "try..catch") and:
explicitly throw the exception
gracefully handle the exception
I have list of IPs like this
val ips = List("ip1", "ip2", "ip3")
I use that list to do http get requests via my wrapper get method, and my wrapper get method will throw BadRequestException if the response status is 400. I understand if I get all success say 200 since myWrapper returns Future[WSResponse], in good case my end result will be List[Future[WSResponse]]
Example snippet
def myresponses(ips:List[String]) = {
ips.map(ip=>myWrapper(ip))
}
My confusion and question is that since myWrapper can throw an exception in case of status 404, will other guys still execute? In short in bad case say where one request gives 404 and say the remaining all give 200, is it going to be the case that I will have List[WSResponse] and for one of the elements it will be an exception? Or it will not be the case and if one Future has failed, the others might not even execute?
They will all execute. If there is an exception, that element will be a failed future. It will still have the type Future[Response], but if you try to Await.result on it, an exception will be thrown. If you try to further transform (map, flatMap, etc.) such failed Future, nothing will happen (the transformation will never be executed).
You can handle those exceptions with .recover or .recoverWith (they are like .map and flatMap, but will only invoke the transformation if the future has failed), or report/clean up it with .onFailure (there is also .onSuccess and .onComplete, that handles both cases).
There is a good tutorial on dealing with scala futures here:
https://docs.scala-lang.org/overviews/core/futures.html
this is a test program:
object Test {
def main(args: Array[String]): Unit = {
// there is an unhandled exception in here, I expect program can remind me, and I can handled it before running.
myException()
}
def myException: Unit ={
throw new Exception
}
}
In Java, when I called a method with unhandling exception, the program will occur error, and tell you add throws declaration or surround with try/catch.
How to know the program have unhandled exceptions before running in Scala?
Scala has a somewhat different philosophy with regards to Exceptions.
The rule of thumb is to not use them unless for something truly exceptional and, thus "let it fail". The reason invoked behind this rule is that, in FP terms, exceptions break referential transparency.
The good practice is to use Either or Option to handle/wrap "errors" rather than throwing exceptions. (the link provided by #Tawkir seems a good read)
Unfortunately this does not help when interfacing with Java code which often uses Exceptions for program control flow, and the compiler will not help you there. A practical way around this is to wrap Exception throwing code with a Try and then call recover or recoverWith to handle these exceptions and, say, wrap them in another structure.
Please note that you can mark a scala method with an #throws annotation to specify the Exception(s) that this method throws, but this should really be used when writing scala code meant to be used by a Java caller expecting an Exception to be thrown.
There's no distinction between checked and unchecked exceptions in the JVM. This is only enforced in the Java compiler, based on whether the class extends RuntimeException or not. Scala compiler doesn't check it, so, there is no way to know, does program have unhandled unchecked exceptions, or not.
This is a rather general question, but hopefully a reasonable one. When is ExecutionContext#reportFailure(Throwable) called?
It doesn't seem to be called in the Scala standard library. I suppose I perhaps should call it in some circumstances? What are these?
This method reports exceptions that cannot be reported otherwise.
It is called when an exception happens during the execution of a callback that has no other way of reporting failure. In particular, calls to Future.onComplete (e.g. via Future.foreach) return Unit and may be executed on any thread, so they have no way of reporting failure back to their callers. When an exception is thrown within onComplete, it is sent to this method.
It is called a couple of times deep within the implementation for Promise in the standard library. See the source.
try onComplete(value) catch { case NonFatal(e) => executor reportFailure e }
An ExecutionContext can implement reportFailure to execute arbitrary code when a future/promise fails. The only thing in the standard library that implements this method is ExecutionContextImpl, which is not in the public API, but found here. This class accepts a reporter: Throwable => Unit function. The default ExecutionContext.Implicits.global uses ExecutionContext.defaultReporter, which simply prints the stack trace to System.err.
If you wanted to customize the behavior, you could need to define your own ExecutionContext. It's difficult to imagine a scenario where you'd want to produce some other side-effect other than logging the stack trace, or some other kind of logging.
I'm using the constructor Future.failed to create a failed future, but the failed future still throws the exception when I think it should not.
The method session.loadAll does throw an exception.
I'm also using the Play Framework
It even happens using a try-catch block
I think that Future.failed is not throwing the exception. It looks like it is, because the stack trace is generated at the place where the exception is created.
So, if you use a method like Await.result, or another method that assumes that a future is successful, you will see the exception re-thrown, but the stack trace will make it look as if it was thrown in Future.failed.
First, I'm not quite sure why you're using a future here because these don't look like asynchronous calls.
To answer your question, however, I'm not entirely sure what is going on here, but it looks like you need to be handling the exception. The consumer of the future should use either Future.onComplete and pattern match a Failure type, or Future.onFailure and pattern match on Throwable types.
Scala docs on Future: http://docs.scala-lang.org/overviews/core/futures.html