6

In akka-http routing I can return Future as a response that implicitly converts to ToResponseMarshaller.

Is there some way to handle timeout of this future? Or timeout of connection in route level? Or one way is to use Await() function?

Right now client can wait response forever.

complete {
   val future = for {
     response <- someIOFunc()
     entity <- someOtherFunc()
   } yield entity
   future.onComplete({
     case Success(result) =>
       HttpResponse(entity = HttpEntity(MediaTypes.`text/xml`, result))
     case Failure(result) =>
       HttpResponse(entity = utils.getFault("fault"))
   })
   future
 }
Jacek Laskowski
  • 72,696
  • 27
  • 242
  • 420
diemust
  • 110
  • 2
  • 7
  • Please explain where timeout is needed in your code? Your code seems wrong: you create HttpResponse in onSuccess and do not set it everywhere and do not return it. If you want to transform result in future use method map – Denis Borovikov Mar 29 '15 at 10:35
  • I need to send response with fault message if someIOFunc() performed for a long time (1 minute for example). Maybe pattern with "onSuccess" is wrong, but this code return right response, when success. It confuses me, but I can't understand how conversion from future to response is working. There is deep layers of abstraction in sources and I can't understand this part – diemust Mar 29 '15 at 10:43
  • Just remove `future` at the end of the block. Futures, like other Scala constructs, are immutable data structures which calling methods on them will return another futures. When you call `onComplete` method, it returns new future with your `HttpResponse`. – Mustafa Simav Mar 30 '15 at 07:53

1 Answers1

13

Adding a timeout to an asynchronous operation means creating a new Future that is completed either by the operation itself or by the timeout:

import akka.pattern.after
val future = ...
val futureWithTimeout = Future.firstCompletedOf(
    future ::
    after(1.second, system.scheduler)(Future.failed(new TimeoutException)) ::
    Nil
  )

The second Future could also hold a successful result that replaces the error, depending on what exactly it is that you want to model.

As a side note: the presented code sample contains dead code, registering an onComplete handler on a Future only makes sense for side-effects but you seem to want to transform the Future’s value and create an HttpEntity from it. That should be done using map and recover:

future
  .map(result => HttpResponse(entity = HttpEntity(MediaTypes.`text/xml`, result)))
  .recover { case ex => HttpResponse(entity = utils.getFault("fault")) }

This would then be the overall return value that is passed to the complete directive.

Roland Kuhn
  • 15,412
  • 2
  • 36
  • 45
  • A little of topic, but I have seen that this is the preferred pattern of using timeouts in Akka. But what happes to the other future when the timeout occurs? It will still run until completed, and occupy a thread in the executor until it is finished, no matter how long? – NilsH Mar 31 '15 at 12:02
  • 3
    Yes, this is by design: holding a `Future` means that you have read-only access to the provided value, and the ability to cancel is something that implies a more exclusive right. Cancellation itself it not really possible on the JVM, but if you hold the `Promise` instead then you can complete it and the code that is calculating the real value can abort when it sees that—this is manual because forceful cancellation is impossible. – Roland Kuhn Mar 31 '15 at 15:38
  • That makes sense. But that also means that a Future that "hangs", will not release it's resources until it completes (or fails at some other level), regardless of duration. What is the proper action to avoid thread starvation in an async scenario like this? – NilsH Apr 08 '15 at 06:45
  • @RolandKuhn, can it ends with "Exceeded configured max-open-requests" exception after some time? Is it possible to set some config that will fill future with error on akka-http side? I think that I have this kind of issue - http://stackoverflow.com/questions/30816965/exceeded-configured-max-open-requests – user2963977 Jun 13 '15 at 22:39