やる気がストロングZERO

やる気のストロングスタイル

SpringBoot @Retryableでリトライがかからない事象にハマった

SpringBoot @Retryableでリトライがかからない事象にハマって時間を消費したので共有

結論

@Retryableアノテーションを付けていても、内部呼び出しだとリトライされない。

以下のような構成で、functionAを外部から叩かれた時、functionBはリトライがかかる想定だったがリトライされなかった。

public void functionA() {
    this.functionB();
}

@Retryable
private void functionB() {
    throw new Exception("例外発生")
}

リトライしたければ外から叩かれるメソッドにアノテーションを付ける必要がある。

以下のコードだと想定通りにリトライされる。

@Retryable
public void functionA() {
    this.functionB();
}

private void functionB() {
    throw new Exception("例外発生")
}

理由

SpringではDIでインスタンス生成を管理できるが、DIで生成されるインスタンスはSpringの機能で一枚ラップされている。
このラッパーによって、アスペクト思考的な機能が提供されている。
@Retryableもその一つで、ラッパーを通してメソッドが呼び出された時、例外をラッパー側でチェックしていて、必要があれば再度実行してくれる仕組みになっていると思われる。

なので、インスタンス内部間のメソッド呼び出しではラッパーが例外を検知できないので、リトライが効かない、という状況になっていたのだと思われる。

アノテーションって付けたら動作すると思ってしまうけど、うまく行かない時のデバッグに時間かかりがち。