Làm thế nào để bạn thực hiện một thử lại bắt?


203

Thử bắt có nghĩa là để giúp xử lý ngoại lệ. Điều này có nghĩa là bằng cách nào đó nó sẽ giúp hệ thống của chúng tôi mạnh mẽ hơn: cố gắng phục hồi sau một sự kiện bất ngờ.

Chúng tôi nghi ngờ điều gì đó có thể xảy ra khi thực hiện và hướng dẫn (gửi tin nhắn), vì vậy nó sẽ được đưa vào thử. Nếu điều đó gần như bất ngờ xảy ra, chúng ta có thể làm một điều gì đó: chúng ta viết bài bắt. Tôi không nghĩ rằng chúng tôi đã gọi để đăng nhập ngoại lệ. Tôi nghĩ rằng khối bắt có nghĩa là cho chúng tôi cơ hội phục hồi từ lỗi.

Bây giờ, giả sử chúng tôi phục hồi từ lỗi vì chúng tôi có thể sửa những gì sai. Nó có thể là siêu tốt đẹp để thử lại:

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

Điều này sẽ nhanh chóng rơi vào vòng lặp vĩnh cửu, nhưng hãy nói rằng fix_the_propet trả về đúng, sau đó chúng tôi thử lại. Cho rằng không có điều đó trong Java, BẠN sẽ giải quyết vấn đề này như thế nào? Điều gì sẽ là mã thiết kế tốt nhất của bạn để giải quyết điều này?

Đây giống như một câu hỏi triết học, cho rằng tôi đã biết những gì tôi yêu cầu không được Java hỗ trợ trực tiếp.


5
Đó là loại ngoại lệ nào?
Bhesh Gurung

23
Tôi thích tên của ngoại lệ của bạn mặc dù. ;)
Rohit Jain

Trong chứng thư, không có nhiều ngoại lệ mà bạn có thể phục hồi. Tôi thừa nhận động lực ban đầu của tôi không phải là một ngoại lệ thực sự, nhưng cách để tránh nếu điều đó sẽ xảy ra gần như không bao giờ: tôi cố gắng remove()từ một java.util.Queue, mà thorws và InvalidElementExceptionkhi hàng đợi trống. Thay vì hỏi nó có trống không, tôi tìm hiểu các hành động trong một lần thử (điều này xảy ra đồng thời trở thành bắt buộc ngay cả với lần trước nếu). Trong trường hợp như vậy, trong catchkhối tôi sẽ yêu cầu nạp lại hàng đợi với nhiều phần tử hơn và sau đó, thử lại. Voila.
Andres Farias

1
Tôi có thể thấy cách làm thông thường này sẽ là truy cập DB, nếu kết nối không kết nối lại được, nếu thất bại thì hãy ném ngoại lệ lớn nếu không hãy thử lại cuộc gọi. Như đã nói, chúng ta có thể thực hiện nó trong một vòng lặp với một kiểm tra ở phía dưới nếu (lỗi <> 0) sau đó quay lại nếu không thì phá vỡ;
Theresa Forster

Câu trả lời:


303

Bạn cần đặt try-catchbên trong một whilevòng lặp như thế này: -

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

Tôi đã thực hiện countmaxTriesđể tránh chạy vào một vòng lặp vô hạn, trong trường hợp ngoại lệ tiếp tục xảy ra trong của bạn try block.


3
Tôi đã nghĩ trong một cái gì đó như thế này lúc đầu, không có maxTries. Cảm ơn câu trả lời!
Andres Farias

6
@AndresFarias .. Vâng, điểm quan trọng nhất trong câu trả lời này là bao gồm a maxTries. Khác nó sẽ chạy vào infinite loopnếu người dùng liên tục cung cấp đầu vào sai, và do đó sẽ không thoát. Bạn được chào đón mặc dù. :)
Rohit Jain

cảm ơn bạn vì điều này - nó đã giúp tôi không phải viết một số mã rất sởn gai ốc!
Ngày lễ David

2
Có thể thêm chức năng Thread.s ngủ () bên trong phần bắt ở đây. Bởi vì trong một số trường hợp như chờ phản hồi của trang trong thư viện Selenium đã trở nên quan trọng. Cảm ơn.
Suat Atan Tiến sĩ

2
Hoạt động tuyệt vời! Đối với người mới bắt đầu: Nếu bạn nhận được vòng lặp vô hạn tích cực, hãy kiểm tra xem Bạn đã thêm "break;" ở cuối khối "thử".
Krzysztof Walczewski

59

Giải pháp "enterprisy" bắt buộc:

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

Và gọi:

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

6
Bạn nên ném lại ngoại lệ nếu lần thử lại lần cuối thất bại, như được thực hiện trong các câu trả lời khác được đưa ra.
cvacca

35

Như thường lệ, thiết kế tốt nhất phụ thuộc vào hoàn cảnh cụ thể. Thông thường, tôi viết một cái gì đó như:

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

Đợi đã, tại sao không có điều kiện bên trong khai báo vòng lặp for: for (int retries = 0; retries <6; retries ++) ??
Didier A.

8
Bởi vì tôi chỉ muốn ném vào lần thử cuối cùng, và do đó, khối bắt cần điều kiện đó, làm cho điều kiện trong dự phòng.
meriton

1
Tôi không nghĩ rằng điều đó continuelà cần thiết ở đó .. Và bạn có thể chỉ cần lật điều kiện if.
Koray Tugay

19

Mặc dù try/catchvào whilelà chiến lược nổi tiếng và tốt, tôi muốn đề nghị bạn gọi đệ quy:

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
Làm thế nào là đệ quy tốt hơn một vòng lặp cho trường hợp sử dụng này?
Dan

7
Dấu vết ngăn xếp có thể trông hơi kỳ lạ trên cái này, bởi vì nó sẽ không limitđếm được phương thức đang được đệ quy? Trái ngược với phiên bản vòng lặp, sẽ ném ở cấp độ 'ban đầu' ...
Clockwork-Muse

7
Chắc chắn trông thanh lịch trên giấy nhưng tôi không chắc chắn đệ quy là cách tiếp cận đúng đắn bằng cách nào đó.
Thomas

3
Tôi không hiểu tại sao đệ quy ở đây quá. Dù sao, tôi nghĩ rằng nó có thể được đơn giản hóa thành:void retry(int times) { (...) if (times==0) throw w; retry(times--);
sinuhepop

8
Đó là thực tế kém để sử dụng đệ quy thay thế cho việc lặp lại đơn thuần. Đệ quy được sử dụng khi bạn muốn đẩy và bật một số dữ liệu.
Hầu tước Lorne

19

Kịch bản chính xác của bạn được xử lý thông qua Failsafe :

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

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

Khá đơn giản.


5
thư viện rất đẹp
Maksim

đối với những người thắc mắc, bạn sẽ cần điều này trong các phụ thuộc cấp độ của bạn - biên dịch 'net.jodah: failafe: 1.1.0'
Shreyas

18

Bạn có thể sử dụng các chú thích AOP và Java từ các khía cạnh jcabi (Tôi là nhà phát triển):

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

Bạn cũng có thể sử dụng @Loggable@LogExceptionchú thích.


Ồ Âm thanh lạ mắt! :)
Alind Billore 7/08/2015

Nên là câu trả lời hàng đầu.
Mohamed Taher Alrefaie

2
Có cách nào để "sửa" lỗi khi lần thử thất bại (một số việc áp dụng có thể khắc phục lần thử tiếp theo) không? xem câu hỏi: fix_the_problem();trong khối bắt
warch

Với số lượng các vấn đề mở và thời gian trôi qua cho các lỗi được thừa nhận không được sửa, tôi sẽ không dựa vào thư viện này.
Michael Lihs

6

Hầu hết các câu trả lời về cơ bản là giống nhau. Của tôi cũng vậy, nhưng đây là hình thức tôi thích

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

Một nhược điểm là bạn cũng gọi fix_the_problemsau lần thử cuối cùng. Đó có thể là một hoạt động tốn kém và có thể lãng phí thời gian.
Joachim Sauer

2
@JoachimSauer Đúng. Bạn có thể if (tryCount < max) fix()- nhưng đây là định dạng của một cách tiếp cận chung; các chi tiết sẽ phụ thuộc vào một trường hợp cụ thể. Ngoài ra còn có một Retasher dựa trên ổi tôi đã xem xét.
Stephen P

4

Giải pháp dựa trên AOP và chú thích mùa xuân:

Cách sử dụng ( @RetryOperationlà chú thích tùy chỉnh của chúng tôi cho công việc):

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

Chúng ta sẽ cần hai thứ để thực hiện điều này: 1. giao diện chú thích và 2. khía cạnh mùa xuân. Đây là một cách để thực hiện những điều sau:

Giao diện chú thích:

import java.lang.annotation.*;

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

Các khía cạnh mùa xuân:

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

Sử dụng một whilevòng lặp với statuscờ địa phương . Khởi tạo cờ như falsevà đặt nó truekhi hoạt động thành công, ví dụ như dưới đây:

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

Điều này sẽ tiếp tục thử lại cho đến khi thành công.

Nếu bạn chỉ muốn thử lại một số lần nhất định thì hãy sử dụng một bộ đếm:

  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
  }

Điều này sẽ thử tối đa 10 lần nếu không thành công cho đến khi đó sẽ thoát nếu thành công trước khi ra tay.


Thay vì kiểm tra !successtrong thời gian của bạn, bạn chỉ có thể thoát ra trong khi thành công là sự thật.
Rohit Jain

1
@RohitJain: Nó trông sạch sẽ hơn đối với tôi.
Yogendra Singh

@YogendraSingh .. Lạ thật. như bạn không sửa đổi successbất cứ nơi nào trong của bạn catch. Vì vậy, nó có vẻ dư thừa để kiểm tra nó, trên mỗi lần chạy catch.
Rohit Jain

@RohitJain: Catch chỉ là sửa dữ liệu. Nó sẽ quay trở lại và chạy lại tuyên bố. Nếu thành công, nó sẽ sửa đổi success. Hãy thử nó.
Yogendra Singh

3

Đây là một câu hỏi cũ nhưng một giải pháp vẫn có liên quan. Đây là giải pháp chung của tôi trong Java 8 mà không cần sử dụng bất kỳ thư viện bên thứ ba nào:

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

Hãy có một trường hợp thử nghiệm như:

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

Ý tưởng hay, một người xây dựng qua lại!
HankTheTank

2

Một cách đơn giản để giải quyết vấn đề sẽ là bọc thử / bắt trong một vòng lặp while và duy trì số đếm. Bằng cách này, bạn có thể ngăn chặn một vòng lặp vô hạn bằng cách kiểm tra số đếm đối với một số biến khác trong khi duy trì nhật ký các lỗi của bạn. Nó không phải là giải pháp tinh tế nhất, nhưng nó sẽ hoạt động.


1

Sử dụng do-while để thiết kế khối thử lại.

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

2
Mã sẽ ném ngoại lệ ban đầu nếu không thành công
lilalinux

1

Trong trường hợp nó hữu ích, một vài lựa chọn để xem xét, tất cả được ném cùng nhau (stopfile thay vì thử lại, ngủ, tiếp tục vòng lặp lớn hơn) tất cả có thể hữu ích.

 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
}

Cử tri xuống xin vui lòng để lại ý kiến ​​tại sao, cảm ơn!
rogerdpack

1
Đây là một sự thiếu hiểu biết tuyệt đối để downvote và không trích dẫn một lý do.
xploreraj

Ngủ ở đó là không rõ ràng vì vòng lặp while sẽ không chờ đợi
João Pimentel Ferreira

1

Bạn có thể sử dụng https://github.com/bnsd55/RetryCatch

Thí dụ:

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

Thay vì new ExampleRunnable()bạn có thể vượt qua chức năng ẩn danh của riêng bạn.


1

Nếu không phải tất cả các ngoại lệ đều đảm bảo thử lại, chỉ một số. Và nếu ít nhất một lần thử phải được thực hiện, Đây là một phương pháp tiện ích thay thế:

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

Sử dụng:

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

0

Tất cả một lần thử làm là cho phép chương trình của bạn thất bại một cách duyên dáng. Trong một tuyên bố bắt, bạn thường cố gắng ghi lại lỗi và có thể khôi phục các thay đổi nếu bạn cần.

bool finished = false;

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

bạn có nghĩa là trái ngược với (!finished)?
Sam tôi đang nói Phục hồi lại

1
@RohitJain nó trông quá giống while(finished). Tôi thích sử dụng phiên bản dài dòng hơn.
Sam tôi đang nói Phục hồi Monica

3
Làm thế nào trên trái đất while(!finished)trông như thế nào while (finished)??
Rohit Jain

@Rohit Bởi vì nó chỉ có một ký tự khác nhau. Tất cả đều được biên dịch xuống cùng một điều. Trong C #, tôi sử dụng phương thức mở rộng Chuỗi IsPopulated()chỉ trả về !IsNullOrEmpty()để đảm bảo rằng ý định của tôi được tất cả các nhà phát triển hiểu.
Michael Blackburn

0

Tôi biết đã có nhiều câu trả lời tương tự ở đây, và của tôi không khác nhiều, nhưng dù sao tôi cũng sẽ đăng nó vì nó liên quan đến một trường hợp / vấn đề cụ thể.

Khi giao dịch với facebook Graph APItrong PHPđôi khi bạn gặp phải lỗi, nhưng ngay lập tức lại cố gắng điều tương tự sẽ cho kết quả dương tính (ví khác nhau huyền diệu lý do Internet mà nằm ngoài phạm vi của câu hỏi này). Trong trường hợp này, không cần sửa bất kỳ lỗi nào, mà chỉ cần thử lại vì có một số "lỗi facebook".

Mã này được sử dụng ngay sau khi tạo phiên facebook:

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

Ngoài ra, bằng cách forđếm vòng lặp xuống 0 ( $attempt--), điều này giúp dễ dàng thay đổi số lần thử trong tương lai.


0

Sau đây là giải pháp của tôi với cách tiếp cận rất đơn giản!

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

                    }
                }

1
vui lòng xem câu trả lời @Rohit Jain cụ thể hơn và không phải là một vòng lặp vô hạn trong các trường hợp tiêu cực.
Chandra Shekhar

0

Tôi không chắc chắn nếu đây là cách "Chuyên nghiệp" để làm điều đó và tôi không hoàn toàn chắc chắn nếu nó hoạt động cho tất cả mọi thứ.

boolean gotError = false;

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


0

Đây là một cách tiếp cận có thể sử dụng lại và chung chung hơn cho Java 8+ mà không yêu cầu các thư viện bên ngoài:

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

Sử dụng:

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

0

Vấn đề với các giải pháp còn lại là, hàm tương ứng cố gắng liên tục mà không có khoảng thời gian ở giữa, do đó làm ngập ngăn xếp.

Tại sao không chỉ trying mỗi giây và quảng cáo vĩnh viễn ?

Đây là một giải pháp sử dụng setTimeoutvà một hàm đệ quy:

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

Thay thế chức năng Run()bằng chức năng hoặc mã mà bạn muốn re trymỗi giây.


0

Hãy dùng thử bằng cách sử dụng chú thích lò xo @R temable, phương thức bên dưới sẽ thử lại trong 3 lần thử khi RuntimeException xảy ra

@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

Đoạn mã dưới đây thực thi một số đoạn mã. Nếu bạn gặp bất kỳ lỗi nào trong khi thực thi đoạn mã, hãy ngủ trong M mili giây và thử lại. Liên kết tham khảo .

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

Đây là giải pháp của tôi tương tự như một số người khác có thể bọc một hàm, nhưng cho phép bạn lấy giá trị trả về của hàm, nếu nó thành công.

    /**
     * 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");
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.