11

私の Java アプリケーションには、リモート呼び出しの失敗に対する再試行ロジックが必要です。これらのリモート呼び出しは次のとおりです。

  • アプリケーション全体に散らばる
  • さまざまなリモート サービス クラスに関連します。

また、再試行ロジックには、さまざまな再試行間隔とさまざまな再試行が含まれる場合があります。

どこから呼び出されたかに応じて適切なメソッド呼び出しを行うことができる汎用の retry() 実装が必要です。以下は、私が探している簡単なコード図です。Java リフレクションを使用してこれを実行できることはわかっていますが、どこかで使用できるフレームワークまたはオープン ソースはありますか?

try {
 ClassA objA = remoteServiceA.call(paramA1, paramA2, ...);
} catch (Exception e){
 ClassA objA = (ClassA)retry(remoteService, listOfParams, ..); // generic method call
}
..

try {
 ClassB objB = remoteServiceB.call(paramB1, paramB2, ...);
} catch (Exception e){
 ClassA objB = (ClassB)retry(remoteService, listOfParams, ..); // generic method call
}
4

8 に答える 8

12

すでに提案したように、AOPおよびJavaアノテーションを使用する必要があります。jcabi-aspectsからの既製のメカニズムをお勧めします(私は開発者です):

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

このブログ投稿も読んでください:http ://www.yegor256.com/2014/08/15/retry-java-method-on-exception.html

更新:CactoosRetryFuncから確認してください。

于 2013-02-03T08:30:30.560 に答える
1

500 ミリ秒ごとに最大 5 回リタイアする必要があるメソッドがあるとします。 現在のクラス:

public class RemoteCaller{
    Service serviceCaller;
    public void remoteCall(String message) {
                serviceCaller.updateDetails( this.message);
                return null;
    }
}

修正されたアプローチ:

public class RetriableHelper<T> implements Callable<T> {

    private Callable<T> task;

    private int numberOfRetries;

    private int numberOfTriesLeft;

    private long timeToWait;


    public RetriableHelper(int numberOfRetries, long timeToWait, Callable<T> task) {
        this.numberOfRetries = numberOfRetries;
        numberOfTriesLeft = numberOfRetries;
        this.timeToWait = timeToWait;
        this.task = task;
    }

    public T call() throws Exception {
        while (true) {
            try {
                return task.call();
            } catch (InterruptedException e) {
                throw e;
            } catch (CancellationException e) {
                throw e;
            } catch (Exception e) {
                numberOfTriesLeft--;
                if (numberOfTriesLeft == 0) {
                    throw e; 
                }
                Thread.sleep(timeToWait);
            }
        }
    }
}


Backend system/remote call class:

public class RemoteCaller{

    Service serviceCaller;

    public void remoteCall(String message) {

        class RemoteCallable implements Callable<Void> {
            String message;
            public RemoteCallable( String message)
            {
                this.message = message;
            }
            public Void call() throws Exception{
                serviceCaller.updateDetails( this.message);
                return null;
            }
        }


        RetriableHelper<Void> retriableHelper = new RetriableHelper<Void>(5, 500, new RemoteCallable( message));
        try {
            retriableHelper.call();
        } catch (Exception e) {
            throw e;
        } 
     }
}
于 2015-06-30T14:51:36.400 に答える
1

これは、 (または一般的には ) を使用できる場所の書籍の例です。Springドキュメントの8.2.7 例およびJava 開発者が AspectJ を学習して使用する必要がある 5 つの理由を参照してください。

基本的に、アスペクトは特定のメソッド (注釈、命名規則などを使用して指定) へのすべての呼び出しをインターセプトし、再試行します。

于 2012-06-06T20:35:39.290 に答える
0

spring を使用している場合は、Aspects を使用することをお勧めします。
それ以外の場合は、以下のサンプル ソリューションが機能します。

public class Test
{
    public static void main(String[] args) throws Exception
    {
        Test test = new Test();
        test.toRunFirst("Hello! This is normal invocation");
        runWithRetry(test, "toRunFirst", "Hello! This is First, called with retry");
        runWithRetry(test, "toRunSecond", "Hello! This is Second, called with retry");
    }


    public void toRunFirst(String s) {
        System.out.println(s);
    }
    public void toRunSecond(String s) {
        System.out.println(s);
    }

    public static Object runWithRetry(Object obj, String methodName, Object... args) throws Exception
    {
        Class<?>[] paramClass = new Class<?>[args.length];
        for(int i=0; i< args.length; i++) {
            paramClass[i] = args[i].getClass();
        }
        Method method = obj.getClass().getDeclaredMethod(methodName, paramClass);

        int retryCount = 2;

        for(int i=0; i< retryCount; i++) {
            try {
                return  method.invoke(obj, args);
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }
}
于 2019-12-09T14:14:00.070 に答える
0

どこからサービスを受けますか? ファクトリを使用して、元のファクトリから取得したサービスをプロキシします。その後、プロキシは再試行を透過的に実装できます。リフレクションで Java Proxy/ProxyGenerators を参照してください。

于 2012-06-06T20:31:38.847 に答える