web-gelistirme-sc.com

Başarısız "yeniden denemek" mantığı için tasarım deseni?

Periyodik olarak aşağıya inen uzak bir uç noktayla bağlantı kurmaya çalışmak için yeniden bir bağlantı mantığı yazıyorum. Temel olarak, kod şöyle görünür:

public void establishConnection() {
    try {
        this.connection = newConnection();
    } catch (IOException e) {
        // connection failed, try again.
        try { Thread.sleep(1000); } catch (InterruptedException e) {};

        establishConnection();
    }
}

Bu genel sorunu, çoğu zaman yukarıdakilere benzer kodlarla çözdüm, ancak sonuçtan büyük ölçüde tatmin olmadığımı hissediyorum. Bu sorunla başa çıkmak için tasarlanmış bir tasarım deseni var mı?

48
Naftuli Kay

Çıkmaya değer bir kütüphane, tanımlanmış bir plana göre otomatik olarak yeniden deneme yapan Sarge .

3
Jonathan

Utanmaz fiş: Yeniden deneme işlemlerine izin vermek için bazı sınıflar uyguladım. Kütüphane henüz kullanıma sunulmadı, ancak github'a çatalla ekleyebilirsiniz. Ve bir çatal var.

Çeşitli esnek stratejilerle bir Retryer inşa edilmesini sağlar. Örneğin:

Retryer retryer = 
    RetryerBuilder.newBuilder()
                  .withWaitStrategy(WaitStrategies.fixedWait(1, TimeUnit.SECOND))
                  .withStopStrategy(StopStrategies.stopAfterAttempt(3))
                  .retryIfExceptionOfType(IOException.class)
                  .build();

Ardından, Retryer ile bir çağrılabilir (veya birkaç tanesini) çalıştırabilirsiniz:

retryer.call(new Callable<Void>() {
    public Void call() throws IOException {
        connection = newConnection();
        return null;
    }
}
30
JB Nizet

Idempotent Retry Pattern 'ı deneyebilirsiniz.

enter image description here

22
GalacticJello

AOP ve Java ek açıklamaları kullanıyorum. jcabi-Aspect (Ben bir geliştiriciyim) içinde hazır bir mekanizma var:

@RetryOnFailure(attempts = 3, delay = 1, unit = TimeUnit.SECONDS)
public void establishConnection() {
  this.connection = newConnection();
}

ps. Ayrıca Cactoos dizinindeki RetryScalar dosyasını da deneyebilirsiniz.

9
yegor256

Failsafe kullanarak (burada yazar):

RetryPolicy retryPolicy = new RetryPolicy()
  .retryOn(IOException.class)
  .withMaxRetries(5)
  .withDelay(1, TimeUnit.SECONDS);

Failsafe.with(retryPolicy).run(() -> newConnection());

Ek açıklama yok, sihir yok, Bahar uygulaması olması gerekmez, vb. Basit ve basit. 

4
Jonathan

Bu Java 8 kodunu this blog 'dan gerçekten beğendim ve sınıf yolunuzda fazladan bir kütüphaneye ihtiyacınız yok.

Bir işlevi yalnızca yeniden deneme sınıfına iletmeniz gerekir.

@Slf4j
public class RetryCommand<T> {

    private int maxRetries;

    RetryCommand(int maxRetries)
    {
        this.maxRetries = maxRetries;
    }

    // Takes a function and executes it, if fails, passes the function to the retry command
    public T run(Supplier<T> function) {
        try {
            return function.get();
        } catch (Exception e) {
            log.error("FAILED - Command failed, will be retried " + maxRetries + " times.");
            return retry(function);
        }
    }

    private T retry(Supplier<T> function) throws RuntimeException {

        int retryCounter = 0;
        while (retryCounter < maxRetries) {
            try {
                return function.get();
            } catch (Exception ex) {
                retryCounter++;
                log.error("FAILED - Command failed on retry " + retryCounter + " of " + maxRetries, ex);
                if (retryCounter >= maxRetries) {
                    log.error("Max retries exceeded.");
                    break;
                }
            }
        }
        throw new RuntimeException("Command failed on all of " + maxRetries + " retries");
    }
}

Ve kullanmak için:

new RetryCommand<>(5).run(() -> client.getThatThing(id));
1
Dherik

Deneyebilirsiniz baharı yeniden deneyin , temiz bir arayüze sahip ve kullanımı kolaydır.

Örnek:

 @Retryable(maxAttempts = 4, backoff = @Backoff(delay = 500))
 public void establishConnection() {
    this.connection = newConnection();
 } 

İstisna durumunda, 500ms'lik bir geri çekilme politikasıyla, construcConnection () yönteminin 4 katına kadar tekrar deneyecek (call) 

1
db80

Ayrıca, istenen işlem üzerinde sadece bir döngü yapan ve sadece döngüden ayrıldığında yapılan bir sarmalayıcı işlevi de oluşturabilirsiniz.

public static void main(String[] args) {
    retryMySpecialOperation(7);
}

private static void retryMySpecialOperation(int retries) {
    for (int i = 1; i <= retries; i++) {
        try {
            specialOperation();
            break;
        }
        catch (Exception e) {
            System.out.println(String.format("Failed operation. Retry %d", i));
        }
    }
}

private static void specialOperation() throws Exception {
    if ((int) (Math.random()*100) % 2 == 0) {
        throw new Exception("Operation failed");
    }
    System.out.println("Operation successful");
}
0
klusht

Java 8 kullanıyorsanız, bu yardımcı olabilir.

import Java.util.function.Supplier;

public class Retrier {
public static <T> Object retry(Supplier<T> function, int retryCount) throws Exception {
     while (0<retryCount) {
        try {
            return function.get();
        } catch (Exception e) {
            retryCount--;
            if(retryCount == 0) {
                throw e;
            }
        }
    }
    return null;
}

public static void main(String[] args) {
    try {
        retry(()-> {
            System.out.println(5/0);
            return null;
        }, 5);
    } catch (Exception e) {
        System.out.println("Exception : " + e.getMessage());
    }
}
}

Teşekkürler,

Praveen R.

0
Ravipati Praveen

hiç denemede özel bir şey yok - bu sınıfa örnek olarak http://www.docjar.com/html/api/org/springframework/jms/listener/DefaultMessageListenerContainer.Java.html yaylı geliştiricilerin bile yeniden deneme için kod yazdığını görebilirler - satır 791 ... 

Kaynaklarla uğraşmak için tavsiye edebileceğim şey Apache commons havuz kütüphanesini almaktır - bunu kontrol edin: http://commons.Apache.org/pool/apidocs/org/Apache/commons/pool/impl/GenericObjectPool.html ve http://commons.Apache.org/pool adresini ziyaret edin

0
Andrey Borisov