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

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

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

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

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

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

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



답변

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.


답변

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

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
    }
});


답변

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

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


답변

비록 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);
    }
}


답변

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

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

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

꽤 간단합니다.


답변

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

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

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


답변

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

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);
}