Scala에서 retry 기능을 구현하는 방법은?

2015-12-27 14:20

java 코드에서 scala 코드로 전환하다 retry 기능이 있어 이 코드를 scala 코드로 좀 더 세련되게 변경할 수 있는 방법이 있지 않을까 하고 찾아봤다.

먼저 자바로 구현된 소스 코드를 보자.

private String sendMessageToFacebook(SocialUser loginUser, String link, String receiverId, String message) {
    String postId = null;
    try {
        FacebookClient facebookClient = createFacebookClient(loginUser);
        int i = 0;
        do {
            if (i > 2) {
                break;
            }

            FacebookType response = facebookClient.publish(receiverId + "/feed", FacebookType.class,
                    Parameter.with("link", link), Parameter.with("message", message));
            postId = response.getId();

            i++;
        } while (postId == null);
        log.debug("connect post id : {}", postId);
    } catch (Throwable e) {
        log.error("Facebook Connection Failed : {}", e.getMessage());
    }
    return postId;
}

자바 소스 코드를 보면 main 로직을 담고 있는 부분보다 retry 처리 코드가 많다. 물론 위 코드도 java8에 추가된 람다를 활용하면 좀 더 깔끔한 형태로 구현할 수 있겠다.

scala에서의 해결방법은 What's the Scala way to implement a retry-able call like this one? 문서에서 찾았다. 이 질문의 답변을 보면 정말 다양한 형태의 scala로 구현한 다양한 retry 함수를 볼 수 있다. 이 중에서 가장 마음에 드는 놈을 골라 사용했다.

  @annotation.tailrec
  private def retry[T](n: Int)(fn: => T): T = {
    Try { fn } match {
      case Success(x) => x
      case _ if n > 1 => retry(n - 1)(fn)
      case Failure(e) => throw e
    }
  }

위와 같이 retry 함수를 추가한 후 위 자바 코드를 다음과 같이 리팩토링했다.

  private def sendMessageToFacebook(loginUser: SocialUser, link: String, receiverId: String, message: String) = {
    retry(3) {
      val facebookClient: FacebookClient = createFacebookClient(loginUser)
      val response: FacebookType = facebookClient.publish(receiverId + "/feed", classOf[FacebookType], Parameter.`with`("link", link), Parameter.`with`("message", message))
      response.getId
    }
  }

한 번에 scala의 모든 맛을 느낄 수 없겠지만 이와 같이 생각날 때마다 scala의 기능을 하나씩 익혀가는 것도 나름 재미있다. 위 retry 함수를 보면 Success와 Failure를 활용해 처리하는 부분이 인상적이다. 앞으로 이와 같은 구현에 좀 더 익숙해지기 위해 노력해 봐야겠다.

1개의 의견 from SLiPP

2016-01-08 22:57

오우, 저도 최근 스칼라로 조금씩 전환하고 있는데 참고하겠습니다. 감사합니다 :)

저는 스프링으로 개발하는 프로젝트에는 항상 Spring-Retry를 사용해서 Retry 기능을 썼는데, 지금은 홈페이지에 가보니 공식프로젝트에 나와 있지 않네요. 깃헙은 있는데.. 업데이트가 꾸준히 이뤄지고 있지는 않은것 같네요. https://github.com/spring-projects/spring-retry

@Service
class Service {
    @Retryable(maxAttempts=12, backoff=@Backoff(delay=100, maxDelay=500))
    public service() {
        // ... do something
    }
}

요런식으로 보통 사용했었는데, 설정도 간편하고 사용도 @Retryable만 붙이면 정해놓은 만큼 Retry가 되서 참 좋더라고요.

의견 추가하기

연관태그

← 목록으로