1 /*
2  *  Make.org Core API
3  *  Copyright (C) 2021 Make.org
4  *
5  * This program is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU Affero General Public License as
7  *  published by the Free Software Foundation, either version 3 of the
8  *  License, or (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU Affero General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Affero General Public License
16  *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
17  *
18  */
19 
20 package org.make.api.technical
21 
22 import akka.pattern.AskTimeoutException
23 
24 import scala.concurrent.{ExecutionContext, Future}
25 
26 object RetryableFuture {
27 
28   @SuppressWarnings(Array("org.wartremover.warts.Recursion"))
29   def retry[T](future: () => Future[T], shouldRetry: Throwable => Boolean, times: Int = 3)(
30     implicit executionContext: ExecutionContext
31   ): Future[T] = {
32     future().recoverWith { error =>
33       if (shouldRetry(error) && times > 0) {
34         retry(future, shouldRetry, times - 1)
35       } else {
36         Future.failed(error)
37       }
38     }
39   }
40 
41   def retryOnAskTimeout[T](future: () => Future[T], times: Int = 3)(
42     implicit executionContext: ExecutionContext
43   ): Future[T] = {
44     retry(future, {
45       case _: AskTimeoutException => true
46       case _                      => false
47     }, times)
48   }
49 
50 }
Line Stmt Id Pos Tree Symbol Tests Code
32 19031 1121 - 1301 ApplyToImplicitArgs scala.concurrent.Future.recoverWith org.make.api.technical.retryablefuturetest future.apply().recoverWith[T](({ @SerialVersionUID(value = 0) final <synthetic> class $anonfun extends scala.runtime.AbstractPartialFunction[Throwable,scala.concurrent.Future[T]] with java.io.Serializable { def <init>(): <$anon: Throwable => scala.concurrent.Future[T]> = { $anonfun.super.<init>(); () }; final override def applyOrElse[A1 <: Throwable, B1 >: scala.concurrent.Future[T]](error: A1, default: A1 => B1): B1 = ((error.asInstanceOf[Throwable]: Throwable): Throwable @unchecked) match { case (defaultCase$ @ _) => if (shouldRetry.apply(error).&&(times.>(0))) RetryableFuture.this.retry[T](future, shouldRetry, times.-(1))(executionContext) else scala.concurrent.Future.failed[Nothing](error) case (defaultCase$ @ _) => default.apply(error) }; final def isDefinedAt(error: Throwable): Boolean = ((error.asInstanceOf[Throwable]: Throwable): Throwable @unchecked) match { case (defaultCase$ @ _) => true case (defaultCase$ @ _) => false } }; new $anonfun() }: PartialFunction[Throwable,scala.concurrent.Future[T]]))(executionContext)
44 18717 1447 - 1561 ApplyToImplicitArgs org.make.api.technical.RetryableFuture.retry RetryableFuture.this.retry[T](future, ((x0$1: Throwable) => x0$1 match { case (_: akka.pattern.AskTimeoutException) => true case _ => false }), times)(executionContext)