Retenter l'execution d'une fonction plusieurs fois en Java

Certains d'entre vous connaissent peut être la fonction javascript Try.these de Prototype.

Elle permet d'exécuter plusieurs fonctions et de retourner la valeur de la première fonction qui ne génère pas d'exception. Cela permet d'essayer plusieurs façons de faire, mais aussi de retenter l'exécution d'une fonction, si on lui passe plusieurs fois la même fonction.

Je vous propose un code qui permet de faire l'équivalent en java. Pour cela J'ai utilisé le patron de conception 'template' et les génériques Java 5. J'ai eu besoin de coder cela afin d'être plus tolérant aux erreurs (retenter plusieurs fois une requête HTTP qui pouvait aboutir à un timeout serveur). Je vous conseille de restreindre le catch de la fonction retry() afin de de ne retenter l'exécution, uniquement pour une exception donnée et de propager les autres exceptions le cas échéant.

Voci le code :

package com.gisgraphy;

public abstract class RetryOnErrorTemplate {

    private int alreadyTry = 0;

    private int numberOfTimesToRetry = 1;
    private T returnvalue = null;

    private RetryOnErrorTemplate retry() throws Exception {
    try {
        returnvalue = tryThat();
        alreadyTry++;
        return this;
    } catch (Exception e) {
        numberOfTimesToRetry--;
        alreadyTry++;
        if (numberOfTimesToRetry == 0) {
        throw e;
        } else {
        return retry();
        }
    }
    }

   
    public abstract T tryThat() throws Exception;

    public T times(int numberOfTry) throws Exception {
    this.numberOfTimesToRetry = numberOfTry;
    retry();
    return returnvalue;

    }


    /**
     * @return The number of times the code has already been try
     */
    public int getAlreadyTry() {
        return alreadyTry;
    }


    /**
     * @return The number of times the code should be try  
     */
    public int getNumberOfTimesToRetry() {
        return numberOfTimesToRetry;
    }


}

Voci le test JUnit 4:

package com.gisgraphy;

import junit.framework.Assert;

import org.junit.Test;

import com.gisgraphy.domain.geoloc.service.geoloc.GisgraphyCommunicationException;

public class RetryOnErrorTemplateTest {

    private static final String THE_RETURNED_VALUE = "The returned value";

    @Test
    public void testRetryWhenCodeThrows() throws Exception {
        RetryOnErrorTemplate<String> retryOnError = new RetryOnErrorTemplate<String>() {
            @Override
            public String tryThat() throws Exception {

                if (true) {
                    throw new GisgraphyCommunicationException();
                }
                return "will never be return";
            }
        };
        try {
            retryOnError.times(3);
            Assert.fail("the code should have throws");
        } catch (GisgraphyCommunicationException ignore) {
        }
        Assert.assertEquals("The number of retry is not the expected one",3, retryOnError.getAlreadyTry());
    }

    @Test
    public void testRetryWhenCodeDoesnTThrows() throws Exception {
        RetryOnErrorTemplate<String> retryOnError = new RetryOnErrorTemplate<String>() {
            @Override
            public String tryThat() throws Exception {
                return THE_RETURNED_VALUE;
            }
        };
        Assert.assertEquals("The returned value is not the expected one",THE_RETURNED_VALUE, retryOnError.times(3));
        Assert.assertEquals("Only one try should have been done",1, retryOnError.getAlreadyTry());
    }

}

La discussion continue ailleurs

URL de rétrolien : https://davidmasclet.gisgraphy.com/index.php?trackback/5

Fil des commentaires de ce billet