Advertisement
mitrakov

Scala Play: withTimeout

Jan 15th, 2018
142
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scala 4.20 KB | None | 0 0
  1. // @deprecated.
  2. // Please note that this way is recommended: https://pastebin.com/H9S4rGJT
  3.  
  4. // 1. Simple Action
  5. class TestController @Inject() (cc: ControllerComponents) extends AbstractController(cc) {
  6.   // add to routes file: GET    /testFuture    controllers.TestController.testFuture
  7.   def testFuture = Action {
  8.     Logger.debug(LocalDateTime.now() + ": Start!")
  9.     Thread.sleep(3000)
  10.     Logger.debug(LocalDateTime.now() + ": Finish!")
  11.     Ok("OK")
  12.   }
  13. }
  14.  
  15.         // Output:
  16.         // [debug] application - 2018-01-15T22:17:56.484: Start!
  17.         // [debug] application - 2018-01-15T22:17:59.484: Finish!
  18.  
  19. // 2. Now make it async:
  20. import scala.concurrent.{ExecutionContext, Future}
  21.  
  22. class TestController @Inject()(cc: ControllerComponents)(implicit ec: ExecutionContext) extends AbstractController(cc) {
  23.   // add to routes file: GET    /testFuture    controllers.TestController.testFuture
  24.   def testFuture: Action[AnyContent] = Action.async {
  25.     Future {
  26.       Logger.debug(LocalDateTime.now() + ": Start!")
  27.       Thread.sleep(3000)
  28.       Logger.debug(LocalDateTime.now() + ": Finish!")
  29.       Ok("OK")
  30.     }
  31.   }
  32. }
  33.  
  34.         // Output:
  35.         // [debug] application - 2018-01-15T22:21:23.310: Start!
  36.         // [debug] application - 2018-01-15T22:21:26.310: Finish!
  37.  
  38. // 3. Let's make work harder!
  39. Thread.sleep(20000)
  40.  
  41.         // Output:
  42.         // [debug] application - 2018-01-15T22:39:31.162: Start!
  43.         // [debug] application - 2018-01-15T22:39:51.163: Finish!
  44.  
  45. // 4. And finally we create a guard function "withTimeout":
  46. // utils/package.scala
  47. import scala.concurrent.duration.FiniteDuration
  48. import scala.concurrent.{ExecutionContext, Future, TimeoutException}
  49.  
  50. import akka.actor.Scheduler
  51. import akka.pattern.after
  52.  
  53. package object utils {
  54.   /**
  55.     * Creates a new [[scala.concurrent.Future Future]] based on a given Future with given timeout
  56.     * @param duration duration for timeout, e.g: {{{5 seconds}}}
  57.     * @param f base Future
  58.     * @param ec external [[scala.concurrent.ExecutionContext ExecutionContext]]
  59.     * @param scheduler external [[akka.actor.Scheduler Scheduler]], e.g:
  60.     *                  {{{implicit val scheduler = actorSystem.scheduler}}}
  61.     * @return new wrapped Future enhanced with timeout
  62.     */
  63.   def withTimeout[T](duration: FiniteDuration)(f: => Future[T])
  64.                     (implicit ec: ExecutionContext, scheduler: Scheduler): Future[T] = {
  65.     val timeoutFut = after(duration, scheduler)(Future.failed(new TimeoutException(s"Future timed out after $duration")))
  66.     Future.firstCompletedOf(Seq(f, timeoutFut))
  67.   }
  68. }
  69.  
  70. // TestController.scala
  71. import java.time.LocalDateTime
  72. import javax.inject.Inject
  73.  
  74. import scala.concurrent.{ExecutionContext, Future}
  75. import scala.concurrent.duration._
  76.  
  77. import akka.actor.ActorSystem
  78. import play.api.Logger
  79. import play.api.mvc.{AbstractController, Action, AnyContent, ControllerComponents}
  80.  
  81. import utils.withTimeout
  82.  
  83. class TestController @Inject()(cc: ControllerComponents, actorSystem: ActorSystem)(implicit ec: ExecutionContext)
  84.   extends AbstractController(cc) {
  85.  
  86.   implicit val scheduler = actorSystem.scheduler
  87.  
  88.   // add to routes file: GET    /testFuture    controllers.TestController.testFuture
  89.   def testFuture: Action[AnyContent] = Action.async {
  90.     withTimeout(5 seconds) {
  91.       Future {
  92.         Logger.debug(LocalDateTime.now() + ": Start!")
  93.         Thread.sleep(20000)
  94.         Logger.debug(LocalDateTime.now() + ": Finish!")
  95.         Ok("OK")
  96.       }
  97.     }
  98.   }
  99. }
  100.  
  101.         // Output:
  102.         // [debug] application - 2018-01-15T22:45:45.316: Start!
  103.         // [error] application -
  104.         //
  105.         // ! @76jgce8bj - Internal server error, for (GET) [/testFuture] ->
  106.         //
  107.         // play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception[[TimeoutException: Future timed out after 5 seconds]]
  108.         //  at play.api.http.HttpErrorHandlerExceptions$.throwableToUsefulException(HttpErrorHandler.scala:255)
  109.         //  ...
  110.         // Caused by: java.util.concurrent.TimeoutException: Future timed out after 5 seconds
  111.         //  at utils.package$.$anonfun$withTimeout$1(package.scala:18)
  112.         //  ...
  113.         // [debug] application - 2018-01-15T22:46:05.316: Finish!
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement