재시도 캐치를 어떻게 구현합니까?


203

Try-catch는 예외 처리에 도움이됩니다. 이는 시스템이보다 강력 해 지도록 도와 줄 것임을 의미합니다. 예기치 않은 이벤트를 복구하십시오.

우리는 실행 및 명령 (메시지 전송)시 무언가가 발생할 수 있으므로 시도에 동봉됩니다. 거의 예상치 못한 일이 발생하면 무언가를 할 수 있습니다. 나는 우리가 예외를 기록하기 위해 전화했다고 생각하지 않습니다. catch 블록은 오류에서 복구 할 수있는 기회를 제공합니다.

이제 잘못된 것을 고칠 수 있기 때문에 오류를 복구한다고 가정 해 봅시다. 다시 시도하는 것이 좋을 수 있습니다.

try{ some_instruction(); }
catch (NearlyUnexpectedException e){
   fix_the_problem();
   retry;
}

이것은 영원히 반복되는 루프에 빠질 것이지만 fix_the_problem이 true를 반환한다고 가정하고 다시 시도하십시오. Java에는 그러한 것이 없다고 가정하면이 문제를 어떻게 해결할 수 있습니까? 이 문제를 해결하기위한 최고의 디자인 코드는 무엇입니까?

이것은 내가 요구하는 것이 Java에 의해 직접 지원되지 않는다는 것을 이미 알고 있다는 철학적 질문과 같습니다.


5
어떤 예외가 있습니까?
Bhesh Gurung

23
그래도 예외 이름이 마음에 듭니다. ;)
Rohit Jain

실제로, 복구 할 수있는 예외는 많지 않습니다. 내 최초의 동기는 진짜 예외 아니었다 인정하지만 거의 결코 발생하지 않을 경우 방법은을 피하기 위해 : 내가하려고 remove()A로부터 java.util.Queue, 어떤 thorws 및 InvalidElementException큐가 비어있는 경우. 비어 있는지 묻지 않고 try-catch의 작업을 소싱합니다 (이전 조건에서는 이전 if 와도 강제 적용됩니다). 이 경우 catch블록 에서 더 많은 요소로 큐를 채우고 다시 시도하십시오. 짜잔
Andres Farias

1
이 작업을 수행하는 일반적인 방법은 연결에 대한 재 연결에 실패한 경우 DB 액세스에 대한 것임을 알 수 있습니다. 실패하면 주요 예외를 처리하고 그렇지 않으면 호출을 다시 시도하십시오. 말했듯이 우리는 if (error <> 0)을 확인한 후 루프에서 할 수 있습니다.
테레사 포스터

답변:


304

try-catch내부 while루프를 다음과 같이 묶어야합니다 .-

int count = 0;
int maxTries = 3;
while(true) {
    try {
        // Some Code
        // break out of loop, or return, on success
    } catch (SomeException e) {
        // handle exception
        if (++count == maxTries) throw e;
    }
}

내가 찍은 countmaxTries예외가 발생 계속해서 경우에 방지하기 위해, 무한 루프로 실행 try block.


3
maxTries없이 처음에는 이와 같은 것을 생각했습니다. 답변 해주셔서 감사합니다!
Andres Farias

6
@AndresFarias .. 예,이 답변에서 가장 중요한 점은을 포함하는 것 maxTries입니다. 그렇지 infinite loop않으면 사용자가 지속적으로 잘못된 입력을 제공하면 종료되어 종료되지 않습니다. 그래도 천만에요 :)
Rohit Jain

이것에 감사합니다. 방금 매우 거친 코드를 작성하지 않아도되었습니다!
David Holiday

2
여기서 catch 안에 Thread.sleep () 함수를 추가 할 수 있습니까? Selenium 라이브러리에서 페이지 응답을 기다리는 것과 같이 어떤 경우에는 중요해졌습니다. 감사.
Suat Atan PhD

2
잘 작동합니다! 초보자 : 양의 무한 루프를 받으면 "break;"를 추가했는지 확인하십시오. "시도"블록의 끝에.
Krzysztof Walczewski

59

필수 "엔터프라이즈"솔루션 :

public abstract class Operation {
    abstract public void doIt();
    public void handleException(Exception cause) {
        //default impl: do nothing, log the exception, etc.
    }
}

public class OperationHelper {
    public static void doWithRetry(int maxAttempts, Operation operation) {
        for (int count = 0; count < maxAttempts; count++) {
            try {
                operation.doIt();
                count = maxAttempts; //don't retry
            } catch (Exception e) {
                operation.handleException(e);
            }
        }
    }
}

그리고 전화 :

OperationHelper.doWithRetry(5, new Operation() {
    @Override public void doIt() {
        //do some stuff
    }
    @Override public void handleException(Exception cause) {
        //recover from the Exception
    }
});

6
주어진 다른 답변에서와 같이 마지막 재 시도에 실패하면 예외를 다시 발생시켜야합니다.
cvacca

35

평소와 같이 최상의 디자인은 특정 상황에 따라 다릅니다. 그러나 일반적으로 다음과 같이 작성합니다.

for (int retries = 0;; retries++) {
    try {
        return doSomething();
    } catch (SomeException e) {
        if (retries < 6) {
            continue;
        } else {
            throw e;
        }
    }
}

잠깐, 왜 for 루프 선언 안에 조건이 없는지 : for (int retries = 0; retries <6; retries ++) ??
Didier A.

8
마지막 시도에만 던지기를 원하기 때문에 catch 블록에 해당 조건이 필요하므로 for for 중복 조건을 만듭니다.
meriton

1
나는 그것이 필요하다고 생각하지 않습니다 continue. 그리고 당신은 단순히 if 조건을 뒤집을 수 있습니다.
Koray Tugay

19

비록 try/catch로는 while잘 알려진 좋은 전략입니다 내가 당신에게 재귀 호출을 제안합니다 :

void retry(int i, int limit) {
    try {

    } catch (SomeException e) {
        // handle exception
        if (i >= limit) {
            throw e;  // variant: wrap the exception, e.g. throw new RuntimeException(e);
        }
        retry(i++, limit);
    }
}

41
이 유스 케이스의 루프보다 재귀가 어떻게 더 좋습니까?
Dan

7
스택 추적은 limit재귀되는 방법의 수를 가지고 있지 않기 때문에 이것에 약간 이상하게 보일 수 있습니다 . 루프 버전과 달리 '원본'레벨에서 던질 것입니다 ...
Clockwork-Muse

7
물론 종이에 우아하게 보이지만 재귀가 어떻게 든 올바른 접근 방식인지 확실하지 않습니다.
토마스

3
왜 재귀도 여기 이해하지 못합니다. 어쨌든, 나는 그것이 다음과 같이 단순화 될 수 있다고 생각합니다.void retry(int times) { (...) if (times==0) throw w; retry(times--);
sinuhepop

8
단순한 반복을 대신하여 재귀를 사용하는 것은 좋지 않습니다. 재귀는 일부 데이터를 푸시하고 팝하려는 경우에 사용됩니다.
Lorne의 후작

19

Failsafe 를 통한 정확한 시나리오 처리 :

RetryPolicy retryPolicy = new RetryPolicy()
  .retryOn(NearlyUnexpectedException.class);

Failsafe.with(retryPolicy)
  .onRetry((r, f) -> fix_the_problem())
  .run(() -> some_instruction());

꽤 간단합니다.


5
아주 좋은 도서관.
Maksim

궁금한 사람들을 위해, 당신은 gradle 의존성에서 이것을 필요로 할 것입니다- 'net.jodah : failsafe : 1.1.0'을 컴파일하십시오
Shreyas

18

jcabi-aspects 에서 AOP 및 Java 주석을 사용할 수 있습니다 (개발자입니다).

@RetryOnFailure(attempts = 3, delay = 5)
public String load(URL url) {
  return url.openConnection().getContent();
}

당신은 또한 사용할 수 @Loggable@LogException주석.


와 ! 멋진 소리! :)
Alind Billore

최고 답변이어야합니다.
Mohamed Taher Alrefaie

2
시도가 실패 할 때 오류를 "수정"할 수있는 방법이 있습니까 (다음 시도를 수정하는 일부 채택이 있습니까)? 질문을 참조하십시오 fix_the_problem();catch 블록에서
warch

공개 된 문제의 양과 수정 된 버그에 대한 시간이 지나면이 라이브러리에 의존하지 않습니다.
Michael Lihs

6

이 답변의 대부분은 본질적으로 동일합니다. 광산도 있지만 이것은 내가 좋아하는 형태입니다.

boolean completed = false;
Throwable lastException = null;
for (int tryCount=0; tryCount < config.MAX_SOME_OPERATION_RETRIES; tryCount++)
{
    try {
        completed = some_operation();
        break;
    }
    catch (UnlikelyException e) {
        lastException = e;
        fix_the_problem();
    }
}
if (!completed) {
    reportError(lastException);
}

한 가지 단점은 fix_the_problem마지막 시도 후에도 전화한다는 것 입니다. 즉 수있는 비용이 많이 드는 작업을하고 시간을 낭비 할 수있다.
Joachim Sauer

2
@JoachimSauer True. 당신은 할 수 if (tryCount < max) fix()있지만 이것은 일반적인 접근법의 형식입니다. 세부 사항은 특정 사례에 따라 다릅니다. 내가 본 구아바 기반 Retryer 도 있습니다 .
Stephen P

4

스프링 AOP 및 주석 기반 솔루션 :

사용법@RetryOperation 작업에 대한 사용자 정의 주석) :

@RetryOperation(retryCount = 1, waitSeconds = 10)
boolean someMethod() throws Exception {
}

이를 위해서는 두 가지가 필요하다. 1. 주석 인터페이스와 2. 스프링 측면. 이를 구현하는 한 가지 방법이 있습니다.

주석 인터페이스 :

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RetryOperation {
    int retryCount();
    int waitSeconds();
}

봄 양상 :

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;

@Aspect @Component 
public class RetryAspect {

    private static final Logger LOGGER = LoggerFactory.getLogger(RetryAspect.class);

    @Around(value = "@annotation(RetryOperation)")
    public Object retryOperation(ProceedingJoinPoint joinPoint) throws Throwable {

        Object response = null;
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        RetryOperation annotation = method.getAnnotation(RetryOperation.class);
        int retryCount = annotation.retryCount();
        int waitSeconds = annotation.waitSeconds();
        boolean successful = false;

        do {
            try {
                response = joinPoint.proceed();
                successful = true;
            } catch (Exception ex) {
                LOGGER.info("Operation failed, retries remaining: {}", retryCount);
                retryCount--;
                if (retryCount < 0) {
                    throw ex;
                }
                if (waitSeconds > 0) {
                    LOGGER.info("Waiting for {} second(s) before next retry", waitSeconds);
                    Thread.sleep(waitSeconds * 1000l);
                }
            }
        } while (!successful);

        return response;
    }
}

3

while로컬 status플래그 와 함께 루프를 사용하십시오 . 플래그를 다음 false과 같이 초기화하고 true작업이 성공하면 아래와 같이 설정하십시오 .

  boolean success  = false;
  while(!success){
     try{ 
         some_instruction(); 
         success = true;
     } catch (NearlyUnexpectedException e){
       fix_the_problem();
     }
  }

성공할 때까지 계속 재 시도합니다.

특정 횟수 만 다시 시도하려면 카운터도 사용하십시오.

  boolean success  = false;
  int count = 0, MAX_TRIES = 10;
  while(!success && count++ < MAX_TRIES){
     try{ 
         some_instruction(); 
         success = true;
     } catch (NearlyUnexpectedException e){
       fix_the_problem();
     }
  }
  if(!success){
    //It wasn't successful after 10 retries
  }

성공하지 못한 경우 최대 10 회 시도한 다음 성공하기 전에 종료됩니다.


!success당신의 시간을 확인하는 대신 , 당신은 성공이되는 동안 휴식을 취할 수 있습니다.
Rohit Jain

1
@RohitJain : 더 깨끗해 보입니다.
Yogendra Singh

@YogendraSingh .. 이상한. 의 success어느 곳에서나 수정하지 않기 때문 catch입니다. 따라서의 모든 실행에서이를 확인하는 것이 불필요한 것 같습니다 catch.
Rohit Jain

@RohitJain : Catch가 데이터를 수정하고 있습니다. 돌아가서 명령문을 다시 실행합니다. 성공하면을 수정합니다 success. 사용해보십시오.
Yogendra Singh

3

이것은 오래된 질문이지만 해결책은 여전히 ​​관련이 있습니다. 타사 라이브러리를 사용하지 않고 Java 8의 일반적인 솔루션은 다음과 같습니다.

public interface RetryConsumer<T> {
    T evaluate() throws Throwable;
}
public interface RetryPredicate<T> {
    boolean shouldRetry(T t);
}
public class RetryOperation<T> {
    private RetryConsumer<T> retryConsumer;
    private int noOfRetry;
    private int delayInterval;
    private TimeUnit timeUnit;
    private RetryPredicate<T> retryPredicate;
    private List<Class<? extends Throwable>> exceptionList;

    public static class OperationBuilder<T> {
        private RetryConsumer<T> iRetryConsumer;
        private int iNoOfRetry;
        private int iDelayInterval;
        private TimeUnit iTimeUnit;
        private RetryPredicate<T> iRetryPredicate;
        private Class<? extends Throwable>[] exceptionClasses;

        private OperationBuilder() {
        }

        public OperationBuilder<T> retryConsumer(final RetryConsumer<T> retryConsumer) {
            this.iRetryConsumer = retryConsumer;
            return this;
        }

        public OperationBuilder<T> noOfRetry(final int noOfRetry) {
            this.iNoOfRetry = noOfRetry;
            return this;
        }

        public OperationBuilder<T> delayInterval(final int delayInterval, final TimeUnit timeUnit) {
            this.iDelayInterval = delayInterval;
            this.iTimeUnit = timeUnit;
            return this;
        }

        public OperationBuilder<T> retryPredicate(final RetryPredicate<T> retryPredicate) {
            this.iRetryPredicate = retryPredicate;
            return this;
        }

        @SafeVarargs
        public final OperationBuilder<T> retryOn(final Class<? extends Throwable>... exceptionClasses) {
            this.exceptionClasses = exceptionClasses;
            return this;
        }

        public RetryOperation<T> build() {
            if (Objects.isNull(iRetryConsumer)) {
                throw new RuntimeException("'#retryConsumer:RetryConsumer<T>' not set");
            }

            List<Class<? extends Throwable>> exceptionList = new ArrayList<>();
            if (Objects.nonNull(exceptionClasses) && exceptionClasses.length > 0) {
                exceptionList = Arrays.asList(exceptionClasses);
            }
            iNoOfRetry = iNoOfRetry == 0 ? 1 : 0;
            iTimeUnit = Objects.isNull(iTimeUnit) ? TimeUnit.MILLISECONDS : iTimeUnit;
            return new RetryOperation<>(iRetryConsumer, iNoOfRetry, iDelayInterval, iTimeUnit, iRetryPredicate, exceptionList);
        }
    }

    public static <T> OperationBuilder<T> newBuilder() {
        return new OperationBuilder<>();
    }

    private RetryOperation(RetryConsumer<T> retryConsumer, int noOfRetry, int delayInterval, TimeUnit timeUnit,
                           RetryPredicate<T> retryPredicate, List<Class<? extends Throwable>> exceptionList) {
        this.retryConsumer = retryConsumer;
        this.noOfRetry = noOfRetry;
        this.delayInterval = delayInterval;
        this.timeUnit = timeUnit;
        this.retryPredicate = retryPredicate;
        this.exceptionList = exceptionList;
    }

    public T retry() throws Throwable {
        T result = null;
        int retries = 0;
        while (retries < noOfRetry) {
            try {
                result = retryConsumer.evaluate();
                if (Objects.nonNull(retryPredicate)) {
                    boolean shouldItRetry = retryPredicate.shouldRetry(result);
                    if (shouldItRetry) {
                        retries = increaseRetryCountAndSleep(retries);
                    } else {
                        return result;
                    }
                } else {
                    // no retry condition defined, no exception thrown. This is the desired result.
                    return result;
                }
            } catch (Throwable e) {
                retries = handleException(retries, e);
            }
        }
        return result;
    }

    private int handleException(int retries, Throwable e) throws Throwable {
        if (exceptionList.contains(e.getClass()) || (exceptionList.isEmpty())) {
            // exception is excepted, continue retry.
            retries = increaseRetryCountAndSleep(retries);
            if (retries == noOfRetry) {
                // evaluation is throwing exception, no more retry left. Throw it.
                throw e;
            }
        } else {
            // unexpected exception, no retry required. Throw it.
            throw e;
        }
        return retries;
    }

    private int increaseRetryCountAndSleep(int retries) {
        retries++;
        if (retries < noOfRetry && delayInterval > 0) {
            try {
                timeUnit.sleep(delayInterval);
            } catch (InterruptedException ignore) {
                Thread.currentThread().interrupt();
            }
        }
        return retries;
    }
}

다음과 같은 테스트 사례를 보자.

@Test
public void withPredicateAndException() {
    AtomicInteger integer = new AtomicInteger();
    try {
        Integer result = RetryOperation.<Integer>newBuilder()
                .retryConsumer(() -> {
                    int i = integer.incrementAndGet();
                    if (i % 2 == 1) {
                        throw new NumberFormatException("Very odd exception");
                    } else {
                        return i;
                    }
                })
                .noOfRetry(10)
                .delayInterval(10, TimeUnit.MILLISECONDS)
                .retryPredicate(value -> value <= 6)
                .retryOn(NumberFormatException.class, EOFException.class)
                .build()
                .retry();
        Assert.assertEquals(8, result.intValue());
    } catch (Throwable throwable) {
        Assert.fail();
    }
}

좋은 생각이야, 이리저리!
HankTheTank

2

이 문제를 해결하는 간단한 방법은 try / catch를 while 루프로 감싸서 카운트를 유지하는 것입니다. 이런 식으로 실패 로그를 유지하면서 다른 변수에 대한 카운트를 확인하여 무한 루프를 방지 할 수 있습니다. 가장 정교한 솔루션은 아니지만 작동합니다.


1

do-while을 사용하여 재시도 블록을 설계하십시오.

boolean successful = false;
int maxTries = 3;
do{
  try {
    something();
    success = true;
  } catch(Me ifUCan) {
    maxTries--;
  }
} while (!successful || maxTries > 0)

2
실패하면 코드는 원래 예외를 던져야한다
lilalinux

1

유용 할 경우 고려해야 할 몇 가지 옵션이 더 있습니다 (모두 재시도 대신 정지 파일, 절전 모드, 더 큰 루프 계속).

 bigLoop:
 while(!stopFileExists()) {
    try {
      // do work
      break;
    }
    catch (ExpectedExceptionType e) {

       // could sleep in here, too.

       // another option would be to "restart" some bigger loop, like
       continue bigLoop;
    }
    // ... more work
}

다운 유권자는 왜, 감사합니다에 대한 의견을 남겨주세요!
rogerdpack

1
이것은 공감하고 이유를 인용하지 않는 단순한 무지입니다.
xploreraj

while 루프 기다릴 것이기 때문에 분명이없는 수면
주앙 멘텔 페레이라

1

https://github.com/bnsd55/RetryCatch 를 사용할 수 있습니다

예:

RetryCatch retryCatchSyncRunnable = new RetryCatch();
        retryCatchSyncRunnable
                // For infinite retry times, just remove this row
                .retryCount(3)
                // For retrying on all exceptions, just remove this row
                .retryOn(ArithmeticException.class, IndexOutOfBoundsException.class)
                .onSuccess(() -> System.out.println("Success, There is no result because this is a runnable."))
                .onRetry((retryCount, e) -> System.out.println("Retry count: " + retryCount + ", Exception message: " + e.getMessage()))
                .onFailure(e -> System.out.println("Failure: Exception message: " + e.getMessage()))
                .run(new ExampleRunnable());

대신 new ExampleRunnable()자신의 익명 함수를 전달할 수 있습니다.


1

모든 예외가 재 시도를 보증하지 않으면 일부만 재 시도해야합니다. 적어도 한 번 시도 해야하는 경우 대체 유틸리티 방법은 다음과 같습니다.

void runWithRetry(Runnable runnable, Class<Exception> exClass, int maxRetries) {
        Exception err = null;
        do {
            maxRetries--;
            try {
                runnable.run();
                err = null;
            } catch (Exception e) {
                if(exClass.isAssignableFrom(e.getClass())){
                    err = e;
                }else {
                    throw e;
                }
            }
        } while (err != null && maxRetries > 0);

        if (err != null) {
            throw err;
        }
    }

용법:

    runWithRetry(() -> {
       // do something
    }, TimeoutException.class, 5)

0

Try-Catch는 프로그램이 정상적으로 실패하도록 허용합니다. catch 문에서는 일반적으로 오류를 기록하려고 시도하고 필요한 경우 변경 사항을 롤백 할 수 있습니다.

bool finished = false;

while(finished == false)
{
    try
    {
        //your code here
        finished = true
    }
    catch(exception ex)
    {
        log.error("there was an error, ex");
    }
}

당신은 반대로 의미 (!finished)합니까?
Sam 나는 오전

1
@RohitJain 너무 좋아 보인다 while(finished). 더 자세한 버전을 사용하는 것을 선호합니다.
Sam 나는 오전

3
지구상의 while(!finished)모습은 어떻습니까 while (finished)??
Rohit Jain

@Rohit 하나의 문자 만 다르기 때문입니다. 그들은 모두 같은 것으로 컴파일됩니다. C #에서는 모든 개발자가 내 의도를 이해하도록하기 위해 IsPopulated()반환되는 String 확장 메서드 를 사용합니다 !IsNullOrEmpty().
Michael Blackburn

0

나는 이미 비슷한 대답이 많이 있다는 것을 알고 있으며, 그다지 다르지 않지만 특정 사례 / 문제를 다루기 때문에 어쨌든 게시 할 것입니다.

를 다룰 때 facebook Graph APIPHP당신이 가끔 오류가 발생하지만, 즉시 다시 시도 (다양한에 대한 긍정적 인 결과를 줄 것 같은 일을 마법 이 질문의 범위를 벗어 인터넷상의 이유로). 이 경우 오류 를 수정할 필요는 없지만 "페이스 북 오류"가 발생하여 다시 시도하면됩니다.

이 코드는 페이스 북 세션을 생성 한 직후에 사용됩니다 :

//try more than once because sometimes "facebook error"
$attempt = 3;
while($attempt-- > 0)
{
    // To validate the session:
    try 
    {
        $facebook_session->validate();
        $attempt = 0;
    } 
    catch (Facebook\FacebookRequestException $ex)
    {
        // Session not valid, Graph API returned an exception with the reason.
        if($attempt <= 0){ echo $ex->getMessage(); }
    } 
    catch (\Exception $ex) 
    {
        // Graph API returned info, but it may mismatch the current app or have expired.
        if($attempt <= 0){ echo $ex->getMessage(); }
    }
}

또한 for루프 카운트를 0 $attempt--으로 줄이면 향후 시도 횟수를 쉽게 변경할 수 있습니다.


0

다음은 매우 간단한 접근 방식으로 내 솔루션입니다!

               while (true) {
                    try {
                        /// Statement what may cause an error;
                        break;
                    } catch (Exception e) {

                    }
                }

1
부정적인 경우에는 더 구체적이고 무한 루프가 아닌 @Rohit Jain 답변을 참조하십시오.
찬드라 셰카

0

이것이 "전문적인"방법인지 확실하지 않으며 모든 것이 효과가 있는지 확실하지 않습니다.

boolean gotError = false;

do {
    try {
        // Code You're Trying
    } catch ( FileNotFoundException ex ) {
        // Exception
        gotError = true;
    }
} while ( gotError = true );


0

다음은 외부 라이브러리가 필요하지 않은 재사용 가능하고 일반적인 Java 8+ 접근 방식입니다.

public interface IUnreliable<T extends Exception>
{
    void tryRun ( ) throws T;
}

public static <T extends Exception> void retry (int retryCount, IUnreliable<T> runnable) throws T {
    for (int retries = 0;; retries++) {
        try {
            runnable.tryRun();
            return;
        } catch (Exception e) {
            if (retries < retryCount) {
                continue;
            } else {
                throw e;
            }
        }
    }
}

용법:

@Test
public void demo() throws IOException {
    retry(3, () -> {
        new File("/tmp/test.txt").createNewFile();
    });
}

0

나머지 솔루션의 문제는 해당 함수가 사이에 시간 간격없이 지속적으로 시도하므로 스택에 초과가 발생한다는 것입니다.

try매 초마다 만 그리고 아 테터 만 안 부릅 니까?

다음은 setTimeout재귀 함수를 사용하는 솔루션입니다 .

(function(){
  try{
    Run(); //tries for the 1st time, but Run() as function is not yet defined
  }
  catch(e){
    (function retry(){
      setTimeout(function(){
        try{
          console.log("trying...");
          Run();
          console.log("success!");
        }
        catch(e){
          retry(); //calls recursively
        }
      }, 1000); //tries every second
    }());
  }
})();



//after 5 seconds, defines Run as a global function
var Run;
setTimeout(function(){
  Run = function(){};
}, 5000);

매초마다 Run()다시 할 함수 또는 코드로 함수 를 교체하십시오 try.


0

springs @Retryable annotation을 사용해보십시오. 런타임 예외가 발생하면 아래의 메소드는 3 번의 시도를 다시 시도합니다.

@Retryable(maxAttempts=3,value= {RuntimeException.class},backoff = @Backoff(delay = 500))
public void checkSpringRetry(String str) {
    if(StringUtils.equalsIgnoreCase(str, "R")) {
        LOGGER.info("Inside retry.....!!");
        throw new RuntimeException();
    }
}

0

스 니펫 아래에서 일부 코드 스 니펫을 실행하십시오. 코드 스 니펫을 실행하는 동안 오류가 발생하면 M 밀리 초 동안 대기 한 후 다시 시도하십시오. 참조 링크 .

public void retryAndExecuteErrorProneCode(int noOfTimesToRetry, CodeSnippet codeSnippet, int sleepTimeInMillis)
  throws InterruptedException {

 int currentExecutionCount = 0;
 boolean codeExecuted = false;

 while (currentExecutionCount < noOfTimesToRetry) {
  try {
   codeSnippet.errorProneCode();
   System.out.println("Code executed successfully!!!!");
   codeExecuted = true;
   break;
  } catch (Exception e) {
   // Retry after 100 milliseconds
   TimeUnit.MILLISECONDS.sleep(sleepTimeInMillis);
   System.out.println(e.getMessage());
  } finally {
   currentExecutionCount++;
  }
 }

 if (!codeExecuted)
  throw new RuntimeException("Can't execute the code within given retries : " + noOfTimesToRetry);
}

0

다음은 일부 다른 것과 비슷한 솔루션으로 함수를 래핑 할 수 있지만 성공하면 함수 반환 값을 얻을 수 있습니다.

    /**
     * Wraps a function with retry logic allowing exceptions to be caught and retires made.
     *
     * @param function the function to retry
     * @param maxRetries maximum number of retires before failing
     * @param delay time to wait between each retry
     * @param allowedExceptionTypes exception types where if caught a retry will be performed
     * @param <V> return type of the function
     * @return the value returned by the function if successful
     * @throws Exception Either an unexpected exception from the function or a {@link RuntimeException} if maxRetries is exceeded
     */
    @SafeVarargs
    public static <V> V runWithRetriesAndDelay(Callable<V> function, int maxRetries, Duration delay, Class<? extends Exception>... allowedExceptionTypes) throws Exception {
        final Set<Class<? extends Exception>> exceptions = new HashSet<>(Arrays.asList(allowedExceptionTypes));
        for(int i = 1; i <= maxRetries; i++) {
            try {
                return function.call();
            } catch (Exception e) {
                if(exceptions.contains(e.getClass())){
                    // An exception of an expected type
                    System.out.println("Attempt [" + i + "/" + maxRetries + "] Caught exception [" + e.getClass() + "]");
                    // Pause for the delay time
                    Thread.sleep(delay.toMillis());
                }else {
                    // An unexpected exception type
                    throw e;
                }
            }
        }
        throw new RuntimeException(maxRetries + " retries exceeded");
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.