レジリエンス機能
As of 7.0, the core Spring Framework includes common resilience features, in particular @Retryable and @ConcurrencyLimit annotations for method invocations as well as programmatic retry support.
@Retryable
@Retryable (Javadoc) は、個々のメソッド (メソッドレベルで宣言されたアノテーションを使用)、または特定のクラス階層内のすべてのプロキシ呼び出しメソッド (型レベルで宣言されたアノテーションを使用) の再試行特性を指定するアノテーションです。
@Retryable
public void sendNotification() {
this.jmsClient.destination("notifications").send(...);
} デフォルトでは、例外がスローされると、メソッド呼び出しが再試行されます。最初の失敗後、最大 3 回の再試行 (maxRetries = 3) が行われ、試行間の遅延は 1 秒になります。
例: |
必要に応じて、各メソッドごとにカスタマイズできます。たとえば、includes 属性と excludes 属性を使用して、再試行する例外を絞り込むことができます。指定された例外型は、失敗した呼び出しによってスローされた例外だけでなく、ネストされた原因とも照合されます。
@Retryable(MessageDeliveryException.class)
public void sendNotification() {
this.jmsClient.destination("notifications").send(...);
}@Retryable(MessageDeliveryException.class) は @Retryable(includes = MessageDeliveryException.class) のショートカットです。 |
高度な使用例では、 カスタム述語は |
または、4 回の再試行と、若干のジッターを伴う指数バックオフ戦略の場合:
@Retryable(
includes = MessageDeliveryException.class,
maxRetries = 4,
delay = 100,
jitter = 10,
multiplier = 2,
maxDelay = 1000)
public void sendNotification() {
this.jmsClient.destination("notifications").send(...);
} 最後になりましたが、@Retryable はリアクティブ戻り型を持つリアクティブメソッドでも機能し、パイプラインを Reactor の再試行機能で装飾します。
@Retryable(maxRetries = 4, delay = 100)
public Mono<Void> sendNotification() {
return Mono.from(...); (1)
}| 1 | この生の Mono は再試行仕様で装飾されます。 |
さまざまな特性の詳細については、@Retryable (Javadoc) で使用可能なアノテーション属性を参照してください。
@Retryable のいくつかの属性には、上記の例で使用されている特別に型指定されたアノテーション属性の代替として、プロパティプレースホルダーと SpEL サポートを提供する String バリアントがあります。 |
@ConcurrencyLimit
@ConcurrencyLimit (Javadoc) は、個々のメソッド (メソッドレベルで宣言されたアノテーションを使用)、または特定のクラス階層内のすべてのプロキシ呼び出しメソッド (型レベルで宣言されたアノテーションを使用) の同時実行制限を指定するアノテーションです。
@ConcurrencyLimit(10)
public void sendNotification() {
this.jmsClient.destination("notifications").send(...);
}これは、制限に達した場合にアクセスをブロックするスレッドプールまたは接続プールのプールサイズ制限の効果と同様に、同時に多数のスレッドからターゲットリソースへのアクセスが防止されることを目的としています。
オプションで制限を 1 に設定して、ターゲットの Bean インスタンスへのアクセスを効果的にロックすることもできます。
@ConcurrencyLimit(1)
public void sendNotification() {
this.jmsClient.destination("notifications").send(...);
} このような制限は、一般的にスレッドプールの制限がない仮想スレッドで特に有用です。非同期タスクの場合、これは SimpleAsyncTaskExecutor (Javadoc) で制約できます。同期呼び出しの場合、このアノテーションは ConcurrencyThrottleInterceptor (Javadoc) を通じて同等の動作を提供します。ConcurrencyThrottleInterceptor (Javadoc) は、Spring Framework 1.0 以降、AOP フレームワークを用いたプログラム的な使用のために提供されています。
@ConcurrencyLimit には、上記の int ベースの例の代替として、プロパティプレースホルダーと SpEL サポートを提供する limitString 属性もあります。 |
回復力のある方法の実現
Spring のコアとなるアノテーションベースの機能の多くと同様に、@Retryable と @ConcurrencyLimit はメタデータとして設計されており、適用するか無視するかを選択できます。レジリエンスアノテーションの処理を有効にする最も便利な方法は、対応する @Configuration クラスで @EnableResilientMethods (Javadoc) を宣言することです。
あるいは、コンテキストで RetryAnnotationBeanPostProcessor または ConcurrencyLimitBeanPostProcessor Bean を定義することで、これらのアノテーションを個別に有効にすることもできます。
プログラムによる再試行のサポート
ApplicationContext に登録された Bean 内のメソッドの再試行セマンティクスを指定するための宣言的なアプローチを提供する @Retryable とは対照的に、RetryTemplate (Javadoc) は任意のコードブロックを再試行するためのプログラム API を提供します。
具体的には、RetryTemplate は構成された RetryPolicy (Javadoc) に基づいて Retryable (Javadoc) 操作を実行し、場合によっては再試行します。
var retryTemplate = new RetryTemplate(); (1)
retryTemplate.execute(
() -> jmsClient.destination("notifications").send(...));| 1 | 暗黙的に RetryPolicy.withDefaults() を使用します。 |
デフォルトでは、再試行可能な操作は、スローされたすべての例外に対して再試行されます。最初の失敗後、最大 3 回の再試行 (maxRetries = 3) が行われ、試行間の遅延は 1 秒になります。
再試行回数のみをカスタマイズする必要がある場合は、以下に示すように RetryPolicy.withMaxRetries() ファクトリメソッドを使用できます。
A retryable operation will be executed at least once and retried at most For example, if |
var retryTemplate = new RetryTemplate(RetryPolicy.withMaxRetries(4)); (1)
retryTemplate.execute(
() -> jmsClient.destination("notifications").send(...));| 1 | Explicitly uses RetryPolicy.withMaxRetries(4). |
If you need to narrow the types of exceptions to retry, that can be achieved via the includes() and excludes() builder methods. The supplied exception types will be matched against an exception thrown by a failed operation as well as nested causes.
var retryPolicy = RetryPolicy.builder()
.includes(MessageDeliveryException.class) (1)
.excludes(...) (2)
.build();
var retryTemplate = new RetryTemplate(retryPolicy);
retryTemplate.execute(
() -> jmsClient.destination("notifications").send(...));| 1 | Specify one or more exception types to include. |
| 2 | Specify one or more exception types to exclude. |
For advanced use cases, you can specify a custom カスタム述語は |
The following example demonstrates how to configure a RetryPolicy with 4 retry attempts and an exponential back-off strategy with a bit of jitter.
var retryPolicy = RetryPolicy.builder()
.includes(MessageDeliveryException.class)
.maxRetries(4)
.delay(Duration.ofMillis(100))
.jitter(Duration.ofMillis(10))
.multiplier(2)
.maxDelay(Duration.ofSeconds(1))
.build();
var retryTemplate = new RetryTemplate(retryPolicy);
retryTemplate.execute(
() -> jmsClient.destination("notifications").send(...));A |
Although the factory methods and builder API for RetryPolicy cover most common configuration scenarios, you can implement a custom RetryPolicy for complete control over the types of exceptions that should trigger a retry as well as the BackOff (Javadoc) strategy to use. Note that you can also configure a customized BackOff strategy via the backOff() method in the RetryPolicy.Builder.