scala/basic

scala 에서 retry 구현하기

wefree 2021. 11. 25. 18:11

문제

cats-effectzio 등의 functional library 를 사용하면, 이미 구현되어 있는 retry 를 쉽게 사용할 수 있다. 혹은 retry library 를 활용할 수도 있다. 간단하게 쓸수 있도록 scala 표준 라이브러리만을 사용해 retry 를 구현해 보자. stackoverflow 를 참고할 수 있다.

 

코드

import scala.annotation.tailrec
import scala.util.{Failure, Success, Try}

object Util {
  @tailrec
  def retry[T](n: Int)(f: => T): Try[T] =
    if (n < 0) {
      Failure(new Exception(s"$n must be greater or equal to 0"))
    } else if (n == 0) {
      Try(f)
    } else {
      Try(f) match {
        case Success(value) => Success(value)
        case Failure(_)     => if (n == 1) Try(f) else retry(n - 1)(f)
      }
    }
}

 

 

AI 코드

import scala.concurrent.{Future, ExecutionContext}
import scala.concurrent.duration._
import scala.util.{Failure, Success}
import java.util.concurrent.Executors

object RetryUtil {
  def retry[T](block: => Future[T], maxRetries: Int, delay: FiniteDuration)
              (implicit ec: ExecutionContext): Future[T] = {
    block.recoverWith {
      case _ if maxRetries > 0 =>
        println(s"Retrying... attempts left: $maxRetries")
        Thread.sleep(delay.toMillis)
        retry(block, maxRetries - 1, delay)
    }
  }
}

// 사용 예제
object Main extends App {
  implicit val ec: ExecutionContext = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(4))

  def unreliableOperation: Future[Int] = Future {
    val random = scala.util.Random
    val value = random.nextInt(10)
    if (value < 8) throw new RuntimeException("Failed operation")
    else value
  }

  val result = RetryUtil.retry(unreliableOperation, 5, 2.seconds)

  result.onComplete {
    case Success(value) => println(s"Operation succeeded with value: $value")
    case Failure(exception) => println(s"Operation failed after retries: ${exception.getMessage}")
  }
}