Spring Security OAuth2のリトライを@Retryableで書く
Spring Security OAuth2のアクセストークン取得で接続失敗に対してリトライを行いたい場合、Spring Retryを使うと簡単に実現できます。
やりたいこと
- Spring BootのアプリでOAuth 2.0クライアントを利用する。
- Spring Security OAuth2でアクセストークンを取得する。(
OAuth2RestTemplate
やFeignRequestInterceptor
は内部でSpring Security OAuth2を利用している) - OAuthクライアントの接続失敗でリトライしたい。
実現方法
Spring Security OAuth2の AccessTokenProvider
にはインターセプタを設定するメソッドが用意されており、アクセストークン取得のリクエストを投げる前後で任意の処理を入れることが可能です。
インターセプタのメソッドにSpring Retryの @Retryable
アノテーションを付けることで、簡単にリトライを実現できます。
@EnableRetry @Configuration class OAuth2Configuration { @Autowired RetryableAccessTokenRequestInterceptor accessTokenRequestInterceptor @Bean AccessTokenProvider accessTokenProvider() { def accessTokenProviders = [ new AuthorizationCodeAccessTokenProvider(), new ImplicitAccessTokenProvider(), new ResourceOwnerPasswordAccessTokenProvider(), new ClientCredentialsAccessTokenProvider() ] // インターセプタを設定する accessTokenProviders*.interceptors = [accessTokenRequestInterceptor()] new AccessTokenProviderChain(accessTokenProviders) } }
@Component class RetryableAccessTokenRequestInterceptor implements ClientHttpRequestInterceptor { // 接続失敗に対するリトライを宣言する @Retryable(value = {ConnectException.class}, backoff = @Backoff(delay = 500)) @Override ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { execution.execute(request, body) } }
あらかじめ、依存関係にSpring Retryを追加しておく必要があります。
実行結果
リトライの様子を確認するため、ログレベルを設定しておきます。
logging.level: # リトライのログ org.springframework.retry: DEBUG # Spring Security OAuth2の通信ログ org.apache.http.wire: DEBUG
アクセストークン取得を実行すると、以下のようなログが出力されます。
o.s.retry.support.RetryTemplate : Retry: count=0 org.apache.http.wire : http-outgoing-1 << "[read] I/O error: Connection reset" o.s.retry.support.RetryTemplate : Checking for rethrow: count=1 o.s.retry.support.RetryTemplate : Retry: count=1 o.s.retry.support.RetryTemplate : Checking for rethrow: count=2 o.s.retry.support.RetryTemplate : Retry: count=2 o.s.retry.support.RetryTemplate : Checking for rethrow: count=3 o.s.retry.support.RetryTemplate : Retry failed last attempt: count=3