[SCALA] 이와 같은 재 시도-수 호출을 구현하는 스칼라 방법은 무엇입니까?
SCALA이와 같은 재 시도-수 호출을 구현하는 스칼라 방법은 무엇입니까?
아직 스칼라에서 초보자와 나는 지금에 다음 코드를 구현하는 방법을 찾고 있어요 :
@Override
public void store(InputStream source, String destination, long size) {
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(size);
final PutObjectRequest request = new PutObjectRequest(
this.configuration.getBucket(), destination, source, metadata);
new RetryableService(3) {
@Override
public void call() throws Exception {
getClient().putObject(request);
}
};
}
무엇 동일한 기능을 다시 시도 가능한 서비스가 구현 만에 스칼라를 구현하는 가장 좋은 방법이 있을까요?
그것은 기본적으로 호출 방법 N 시간을 호출, 그들 모두는 그들이 그것을에 이동 성공할 경우를 제외하고는 다음 발생하지 않을 경우. 이것은 아무것도 반환하지 않습니다하지만 내가 값을 반환 수 있습니다 또 다른 버전이 (그래서, 자바에서 두 개의 클래스를) 나는 내가 스칼라에서 하나의 클래스 / 기능을 할 수 있으리라 생각합니다.
어떤 아이디어?
편집하다
다음과 같이 자바의 현재 구현은 다음과 같습니다
public abstract class RetryableService {
private static final JobsLogger log = JobsLogger
.getLogger(RetryableService.class);
private int times;
public RetryableService() {
this(3);
}
public RetryableService(int times) {
this.times = times;
this.run();
}
private void run() {
RuntimeException lastExceptionParent = null;
int x = 0;
for (; x < this.times; x++) {
try {
this.call();
lastExceptionParent = null;
break;
} catch (Exception e) {
lastExceptionParent = new RuntimeException(e);
log.errorWithoutNotice( e, "Try %d caused exception %s", x, e.getMessage() );
try {
Thread.sleep( 5000 );
} catch (InterruptedException e1) {
log.errorWithoutNotice( e1, "Sleep inside try %d caused exception %s", x, e1.getMessage() );
}
}
}
try {
this.ensure();
} catch (Exception e) {
log.error(e, "Failed while ensure inside RetryableService");
}
if ( lastExceptionParent != null ) {
throw new IllegalStateException( String.format( "Failed on try %d of %s", x, this ), lastExceptionParent);
}
}
public void ensure() throws Exception {
// blank implementation
}
public abstract void call() throws Exception;
}
해결법
-
==============================
1.재귀 + 최고 수준의 기능에 의해 이름 매개 변수는 멋진 ==.
재귀 + 최고 수준의 기능에 의해 이름 매개 변수는 멋진 ==.
def retry[T](n: Int)(fn: => T): T = { try { fn } catch { case e => if (n > 1) retry(n - 1)(fn) else throw e } }
사용법은 다음과 같이이다 :
retry(3) { // insert code that may fail here }
편집 : @ themel의 대답에 의해 영감을 약간 변형. 코드 중 하나 개 적은 라인 :-)
def retry[T](n: Int)(fn: => T): T = { try { fn } catch { case e if n > 1 => retry(n - 1)(fn) } }
편집 다시는 : 재귀는 스택 추적에 여러 통화를 추가 한 나를 귀찮게. 어떤 이유로, 컴파일러는 캐치 처리기에 최적화 꼬리 재귀는 할 수 없습니다. 꼬리 재귀되지 캐치 처리기에서, 그래도 잘 최적화 :-)
@annotation.tailrec def retry[T](n: Int)(fn: => T): T = { val r = try { Some(fn) } catch { case e: Exception if n > 1 => None } r match { case Some(x) => x case None => retry(n - 1)(fn) } }
편집 다시 한번 : 분명히 나는 다시오고이 답변에 대한 대안을 계속 추가 할에게 취미를 만들려고하고 있습니다. 여기에 옵션을 사용하지만, 기능은 관용적 스칼라없는 단락 복귀를 사용하는 것보다 좀 더 간단합니다 꼬리 재귀 버전입니다.
@annotation.tailrec def retry[T](n: Int)(fn: => T): T = { try { return fn } catch { case e if n > 1 => // ignore } retry(n - 1)(fn) }
스칼라 2.10 업데이트합니다. 내 취미이기 때문에, 나는 가끔이 답변을 다시 방문. 꼬리 재귀 방식으로 재 시도를 구현하는 깨끗한 방법을 제공합니다 도입 시도로 스칼라 2.10.
// Returning T, throwing the exception on failure @annotation.tailrec def retry[T](n: Int)(fn: => T): T = { util.Try { fn } match { case util.Success(x) => x case _ if n > 1 => retry(n - 1)(fn) case util.Failure(e) => throw e } } // Returning a Try[T] wrapper @annotation.tailrec def retry[T](n: Int)(fn: => T): util.Try[T] = { util.Try { fn } match { case util.Failure(_) if n > 1 => retry(n - 1)(fn) case fn => fn } }
-
==============================
2.scalaz.concurrent.Task [T]의 방법이있다 : http://docs.typelevel.org/api/scalaz/nightly/#scalaz.concurrent.Task
scalaz.concurrent.Task [T]의 방법이있다 : http://docs.typelevel.org/api/scalaz/nightly/#scalaz.concurrent.Task
def retry(delays: Seq[Duration], p: (Throwable) ⇒ Boolean = _.isInstanceOf[Exception]): Task[T]
태스크 [T]를, 당신은 재시도 사이의 지연은 지연 매개 변수에 의해 정의되는 시간의 특정 번호를 재 시도하는 새로운 작업 [T]를 만들 수 있습니다 감안할 때. 예컨대 :
// Task.delay will lazily execute the supplied function when run val myTask: Task[String] = Task.delay(???) // Retry four times if myTask throws java.lang.Exception when run val retryTask: Task[String] = myTask.retry(Seq(20.millis, 50.millis, 100.millis, 5.seconds)) // Run the Task on the current thread to get the result val result: String = retryTask.run
-
==============================
3.여기에 하나의 가능한 구현은 다음과 같습니다
여기에 하나의 가능한 구현은 다음과 같습니다
def retry[T](times: Int)(fn: => T) = (1 to times).view flatMap (n => try Some(fn) catch {case e: Exception => None}) headOption
이처럼 사용할 수 있습니다 :
retry(3) { getClient.putObject(request) }
재시도 일부 [T] 몸이 성공적으로 처리하지 않고 아무도 경우 몸은 던지는 경우 예외를 반환합니다.
마지막으로 예외를 보블 싶은 경우에, 당신은 매우 유사한 접근 방식을 취할 수 대신 옵션 중 하나를 사용합니다 :
def retry[T](times: Int)(fn: => T) = { val tries = (1 to times).toStream map (n => try Left(fn) catch {case e: Exception => Right(e)}) tries find (_ isLeft) match { case Some(Left(result)) => result case _ => throw tries.reverse.head.right.get } }
또한, 대신 단지 마지막 예외를 필요없이 끝에서 볼 수 있듯이, 나는 그들 모두를 가지고있다. 당신이 원한다면 당신은 또한 일부 AggregatingException에서 그 (것)들을 포장 할 수 있으며 다음을 던져. (편의상, 난 그냥 마지막으로 예외를 발생)
-
==============================
4.나는이 좋을 것 -
나는이 좋을 것 -
def retry[T](n: Int)(code: => T) : T = { var res : Option[T] = None var left = n while(!res.isDefined) { left = left - 1 try { res = Some(code) } catch { case t: Throwable if left > 0 => } } res.get }
그렇습니다:
scala> retry(3) { println("foo"); } foo scala> retry(4) { throw new RuntimeException("nope"); } java.lang.RuntimeException: nope at $anonfun$1.apply(<console>:7) at $anonfun$1.apply(<console>:7) at .retry(<console>:11) at .<init>(<console>:7) at .<clinit>(<console>) at RequestResult$.<init>(<console>:9) at RequestResult$.<clinit>(<console>) at RequestResult$scala_repl_result(<console>) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$17.apply(Interpreter.scala:988) at scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$17.apply(Interpreter.... scala> var i = 0 ; i: Int = 0 scala> retry(3) { i = i + 1; if(i < 3) throw new RuntimeException("meh");} scala> i res3: Int = 3
아마 스칼라 더 관용적으로 개선 될 수 있지만 어쨌든 마음으로 전체 표준 라이브러리를 알고 독자를 필요로 한 라이너의 큰 팬이 아니다.
-
==============================
5.당신은 scala.util.control.Exception 사용하여 기능적인 스타일의 생각을 표현할 수있다 :
당신은 scala.util.control.Exception 사용하여 기능적인 스타일의 생각을 표현할 수있다 :
@annotation.tailrec def retry[T](n: Int)(fn: => T): T = Exception.allCatch.either(fn) match { case Right(v) => v; case Left(e) if (n <= 1) => throw e; case _ => retry(n - 1)(fn); }
우리가 볼 수 있듯이, 꼬리 재귀 여기에 사용할 수 있습니다.
이 방법은 당신이 유일한 예외의 특정 부분 집합을 재 시도 할 수 있도록, 캐치 용기 변수화 재 시도의 최종 버전이 같을 수 그래서 등 파이널 라이저를 추가 할 수있는 당신에게 추가 혜택을 제공합니다 :
/** Retry on any exception, no finalizers. */ def retry[T](n: Int)(fn: => T): T = retry(Exception.allCatch[T], n)(fn); /** Parametrized retry. */ @annotation.tailrec def retry[T](theCatch: Exception.Catch[T], n: Int)(fn: => T): T = theCatch.either(fn) match { case Right(v) => v; case Left(e) if (n <= 1) => throw e; case _ => retry(theCatch, n - 1)(fn); }
이, 당신은 복잡한 물건을 같이 할 수 있습니다 :
retry(Exception.allCatch andFinally { print("Finished.") }, 3) { // your scode }
-
==============================
6.재시라는이 도움이 될 수 있습니다 기존 라이브러리가있다, 구아바 - 재 시도라고 너무 자바 라이브러리가있다.
재시라는이 도움이 될 수 있습니다 기존 라이브러리가있다, 구아바 - 재 시도라고 너무 자바 라이브러리가있다.
여기에 재 시도를 사용하는 몇 가지 예입니다 :
// retry 4 times val future = retry.Directly(4) { () => doSomething } // retry 3 times pausing 30 seconds in between attempts val future = retry.Pause(3, 30.seconds) { () => doSomething } // retry 4 times with a delay of 1 second which will be multipled // by 2 on every attempt val future = retry.Backoff(4, 1.second) { () => doSomething }
-
==============================
7.수락 솔루션과 같은 I,하지만 예외를 확인하시기 바랍니다 것은 치명적이다 :
수락 솔루션과 같은 I,하지만 예외를 확인하시기 바랍니다 것은 치명적이다 :
// Returning T, throwing the exception on failure @annotation.tailrec def retry[T](n: Int)(fn: => T): T = { Try { fn } match { case Success(x) => x case _ if n > 1 && NonFatal(e) => retry(n - 1)(fn) case Failure(e) => throw e } }
당신은 스레드 인터럽트 아니 일반적으로 제어 흐름 예외를 다시 시도 할, 그리고하지 않습니다 ...
-
==============================
8.당신은 당신이 시도하는 예외의 제어를 원하는 경우에, 당신은 scala.util.control.Exception의 방법을 사용할 수 있습니다 :
당신은 당신이 시도하는 예외의 제어를 원하는 경우에, 당신은 scala.util.control.Exception의 방법을 사용할 수 있습니다 :
import java.io._ import scala.util.control.Exception._ def ioretry[T](n: Int)(t: => T) = ( Iterator.fill(n){ failing[T](classOf[IOException]){ Option(t) } } ++ Iterator(Some(t)) ).dropWhile(_.isEmpty).next.get
(작성, 그것은 또한 널 (null)에 다시 시도 것이다. 옵션 (t) 부분이, 널 (null)을 반환 할 대신 반복자 채우기 내부) 일부 (t를 사용하는 경우.)
하자이이 밖으로 시도
class IoEx(var n: Int) { def get = if (n>0) { n -= 1; throw new IOException } else 5 } val ix = new IoEx(3)
작동합니까?
scala> ioretry(4) { ix.get } res0: Int = 5 scala> ix.n = 3 scala> ioretry(2) { ix.get } java.io.IOException at IoEx.get(<console>:20) ... scala> ioretry(4) { throw new Exception } java.lang.Exception at $anonfun$1.apply(<console>:21) ...
외모 좋은!
-
==============================
9.나는에 다시 시도하는 예외를 필터링 할 수 있도록 이전의 대답을 적응 결국 :
나는에 다시 시도하는 예외를 필터링 할 수 있도록 이전의 대답을 적응 결국 :
/** * Attempt 'fn' up to 'attempts' times, retrying only if 'forExceptions' returns true for retry-able exceptions. */ def retry[T](attempts: Int, forExceptions: (Throwable) => Boolean)(fn: => T): T = { // toStream creates a lazily evaluated list, which we map to a try/catch block resulting in an Either val tries = (1 to attempts).toStream map { n => try Left(fn) catch { case e if forExceptions(e) => Right(e) } } // find the first 'Either' where left is defined and return that, or if not found, return last // exception thrown (stored as 'right'). The cool thing is that because of lazy evaluation, 'fn' is only // evaluated until it success (e.g., until Left is found) tries find (_ isLeft) match { case Some(Left(result)) => result case _ => throw tries.reverse.head.right.get } }
두 가지 방법으로 호출 할 수 있습니다 :
val result = retry(4, _.isInstanceOf[SomeBadException]) { boom.doit() }
또는 (반환 값에 대해 걱정하지 않는다 또한 버전을 표시) 부분 기능
def pf: PartialFunction[Throwable, Boolean] = { case x: SomeOtherException => true case _ => false } retry(4, pf) { boom.doit() }
-
==============================
10.
//Here is one using Play framework def retry[T](times:Int)(block: => Future[T])(implicit ctx: ExecutionContext):Future[T] = { type V = Either[Throwable,T] val i:Iterator[Future[Option[V]]] = Iterator.continually(block.map(t => Right(t)).recover { case e => Left(e) }.map(t => Some(t))) def _retry:Iteratee[V,V] = { def step(ctr:Int)(i:Input[V]):Iteratee[V,V] = i match { case Input.El(e) if (e.isRight) => Done(e,Input.EOF) case _ if (ctr < times) => Cont[V,V](i => step(ctr + 1)(i)) case Input.El(e) => Done(e,Input.EOF) } Cont[V,V](i => step(0)(i)) } Enumerator.generateM(i.next).run(_retry).flatMap { _ match { case Right(t) => future(t) case Left(e) => Future.failed(e) }} }
-
==============================
11.이 프로젝트는 서로 다른 재시도 메커니즘에 대한 몇 가지 좋은 구현을 제공하는 것 https://github.com/hipjim/scala-retry
이 프로젝트는 서로 다른 재시도 메커니즘에 대한 몇 가지 좋은 구현을 제공하는 것 https://github.com/hipjim/scala-retry
// define the retry strategy implicit val retryStrategy = RetryStrategy.fixedBackOff(retryDuration = 1.seconds, maxAttempts = 2) // pattern match the result val r = Retry(1 / 1) match { case Success(x) => x case Failure(t) => log("I got 99 problems but you won't be one", t) }
-
==============================
12.이 솔루션은 (? 누가 이유를 알고있다), 그러나 드문 시도의 경우 옵션이 될 것입니다 어떤 이유로 꼬리 재귀에 컴파일러에 의해 최적화되어 있지 않습니다 :
이 솔루션은 (? 누가 이유를 알고있다), 그러나 드문 시도의 경우 옵션이 될 것입니다 어떤 이유로 꼬리 재귀에 컴파일러에 의해 최적화되어 있지 않습니다 :
def retry[T](n: Int)(f: => T): T = { Try { f } recover { case _ if n > 1 => retry(n - 1)(f) } get }
용법:
val words: String = retry(3) { whatDoesTheFoxSay() }
대답의 끝. 정지는 여기에 읽기
def reTry[T](n: Int)(f: => T): Try[T] = { Try { f } recoverWith { case _ if n > 1 => reTry(n - 1)(f) } }
용법:
// previous usage section will be identical to: val words: String = reTry(3) { whatDoesTheFoxSay() } get // Try as a result: val words: Try[String] = reTry(3) { whatDoesTheFoxSay() }
def retry[T](n: Int)(f: => Try[T]): Try[T] = { f recoverWith { case _ if n > 1 => reTry(n - 1)(f) } }
용법:
// the first usage section will be identical to: val words: String = retry(3) { Try(whatDoesTheFoxSay()) } get // if your function returns Try: def tryAskingFox(): Try = Failure(new IllegalStateException) val words: Try[String] = retry(3) { tryAskingFox() }
-
==============================
13.시도 간 일시와 재사용 가능한 개체 / 방법
시도 간 일시와 재사용 가능한 개체 / 방법
Retry(3, 2 seconds) { /* some code */ }
암호:
object Retry { def apply[A](times: Int, pause: Duration)(code: ⇒ A): A = { var result: Option[A] = None var remaining = times while (remaining > 0) { remaining -= 1 try { result = Some(code) remaining = 0 } catch { case _ if remaining > 0 ⇒ Thread.sleep(pause.toMillis) } } result.get } }
from https://stackoverflow.com/questions/7930814/whats-the-scala-way-to-implement-a-retry-able-call-like-this-one by cc-by-sa and MIT license
'SCALA' 카테고리의 다른 글
[SCALA] 어떻게 미래를위한 미세 조정 스레드 풀을 구성하는 방법? (0) | 2019.11.07 |
---|---|
[SCALA] 스칼라 : 목록 [미래] 미래 [목록]에 실패 미래를 무시 (0) | 2019.11.07 |
[SCALA] 함수 프로그래밍 스칼라는지도 왼쪽 접어서 [마감] (0) | 2019.11.07 |
[SCALA] 반복자 대보기 대 스트림 (0) | 2019.11.07 |
[SCALA] 방법 인 IntelliJ 아이디어와 SBT 프로젝트를 만드는 방법? (0) | 2019.11.07 |