Allow Retry on choosen status codes
- Add a new autoconfig property spring.ai.retry.on-http-codes that list status codes (scuh as 429) for which the retry should be attemptd. - Updated the docs. Resolves #433
This commit is contained in:
@@ -50,7 +50,7 @@ import org.springframework.util.MimeTypeUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@SpringBootTest(classes = AnthropicTestConfiguration.class)
|
||||
@SpringBootTest(classes = AnthropicTestConfiguration.class, properties = "spring.ai.retry.on-http-codes=429")
|
||||
@EnabledIfEnvironmentVariable(named = "ANTHROPIC_API_KEY", matches = ".+")
|
||||
class AnthropicChatClientIT {
|
||||
|
||||
|
||||
@@ -67,7 +67,8 @@ The prefix `spring.ai.retry` is used as the property prefix that lets you config
|
||||
| spring.ai.retry.backoff.multiplier | Backoff interval multiplier. | 5
|
||||
| spring.ai.retry.backoff.max-interval | Maximum backoff duration. | 3 min.
|
||||
| spring.ai.retry.on-client-errors | If false, throw a NonTransientAiException, and do not attempt retry for `4xx` client error codes | false
|
||||
| spring.ai.retry.exclude-on-http-codes | List of HTTP status codes that should not trigger a retry (e.g. to throw NonTransientAiException). | empty
|
||||
| spring.ai.retry.exclude-on-http-codes | List of HTTP status codes that should NOT trigger a retry (e.g. to throw NonTransientAiException). | empty
|
||||
| spring.ai.retry.on-http-codes | List of HTTP status codes that should trigger a retry (e.g. to throw TransientAiException). | empty
|
||||
|====
|
||||
|
||||
NOTE: currently the retry policies are not applicable for the streaming API.
|
||||
|
||||
@@ -63,6 +63,7 @@ The prefix `spring.ai.retry` is used as the property prefix that lets you config
|
||||
| spring.ai.retry.backoff.max-interval | Maximum backoff duration. | 3 min.
|
||||
| spring.ai.retry.on-client-errors | If false, throw a NonTransientAiException, and do not attempt retry for `4xx` client error codes | false
|
||||
| spring.ai.retry.exclude-on-http-codes | List of HTTP status codes that should not trigger a retry (e.g. to throw NonTransientAiException). | empty
|
||||
| spring.ai.retry.on-http-codes | List of HTTP status codes that should trigger a retry (e.g. to throw TransientAiException). | empty
|
||||
|====
|
||||
|
||||
==== Connection Properties
|
||||
|
||||
@@ -63,6 +63,7 @@ The prefix `spring.ai.retry` is used as the property prefix that lets you config
|
||||
| spring.ai.retry.backoff.max-interval | Maximum backoff duration. | 3 min.
|
||||
| spring.ai.retry.on-client-errors | If false, throw a NonTransientAiException, and do not attempt retry for `4xx` client error codes | false
|
||||
| spring.ai.retry.exclude-on-http-codes | List of HTTP status codes that should not trigger a retry (e.g. to throw NonTransientAiException). | empty
|
||||
| spring.ai.retry.on-http-codes | List of HTTP status codes that should trigger a retry (e.g. to throw TransientAiException). | empty
|
||||
|====
|
||||
|
||||
==== Connection Properties
|
||||
|
||||
@@ -63,6 +63,7 @@ The prefix `spring.ai.retry` is used as the property prefix that lets you config
|
||||
| spring.ai.retry.backoff.max-interval | Maximum backoff duration. | 3 min.
|
||||
| spring.ai.retry.on-client-errors | If false, throw a NonTransientAiException, and do not attempt retry for `4xx` client error codes | false
|
||||
| spring.ai.retry.exclude-on-http-codes | List of HTTP status codes that should not trigger a retry (e.g. to throw NonTransientAiException). | empty
|
||||
| spring.ai.retry.on-http-codes | List of HTTP status codes that should trigger a retry (e.g. to throw TransientAiException). | empty
|
||||
|====
|
||||
|
||||
==== Connection Properties
|
||||
|
||||
@@ -64,6 +64,7 @@ The prefix `spring.ai.retry` is used as the property prefix that lets you config
|
||||
| spring.ai.retry.backoff.max-interval | Maximum backoff duration. | 3 min.
|
||||
| spring.ai.retry.on-client-errors | If false, throw a NonTransientAiException, and do not attempt retry for `4xx` client error codes | false
|
||||
| spring.ai.retry.exclude-on-http-codes | List of HTTP status codes that should not trigger a retry (e.g. to throw NonTransientAiException). | empty
|
||||
| spring.ai.retry.on-http-codes | List of HTTP status codes that should trigger a retry (e.g. to throw TransientAiException). | empty
|
||||
|====
|
||||
|
||||
==== Connection Properties
|
||||
|
||||
@@ -89,6 +89,7 @@ The prefix `spring.ai.retry` is used as the property prefix that lets you config
|
||||
| spring.ai.retry.backoff.max-interval | Maximum backoff duration. | 3 min.
|
||||
| spring.ai.retry.on-client-errors | If false, throw a NonTransientAiException, and do not attempt retry for `4xx` client error codes | false
|
||||
| spring.ai.retry.exclude-on-http-codes | List of HTTP status codes that should not trigger a retry (e.g. to throw NonTransientAiException). | empty
|
||||
| spring.ai.retry.on-http-codes | List of HTTP status codes that should trigger a retry (e.g. to throw TransientAiException). | empty
|
||||
|====
|
||||
|
||||
|
||||
|
||||
@@ -82,18 +82,19 @@ public class SpringAiRetryAutoConfiguration {
|
||||
if (response.getStatusCode().isError()) {
|
||||
String error = StreamUtils.copyToString(response.getBody(), StandardCharsets.UTF_8);
|
||||
String message = String.format("%s - %s", response.getStatusCode().value(), error);
|
||||
/**
|
||||
* Thrown on 4xx client errors, such as 401 - Incorrect API key
|
||||
* provided, 401 - You must be a member of an organization to use the
|
||||
* API, 429 - Rate limit reached for requests, 429 - You exceeded your
|
||||
* current quota , please check your plan and billing details.
|
||||
*/
|
||||
|
||||
// Explicitly configured transient codes
|
||||
if (properties.getOnHttpCodes().contains(response.getStatusCode().value())) {
|
||||
throw new TransientAiException(message);
|
||||
}
|
||||
|
||||
// onClientErrors - If true, do not throw a NonTransientAiException,
|
||||
// and do not attempt retry for 4xx client error codes, false by
|
||||
// default.
|
||||
if (!properties.isOnClientErrors() && response.getStatusCode().is4xxClientError()) {
|
||||
throw new NonTransientAiException(message);
|
||||
}
|
||||
|
||||
// Explicitly configured non-transient codes
|
||||
if (!CollectionUtils.isEmpty(properties.getExcludeOnHttpCodes())
|
||||
&& properties.getExcludeOnHttpCodes().contains(response.getStatusCode().value())) {
|
||||
|
||||
@@ -54,6 +54,11 @@ public class SpringAiRetryProperties {
|
||||
*/
|
||||
private List<Integer> excludeOnHttpCodes = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* List of HTTP status codes that should trigger a retry.
|
||||
*/
|
||||
private List<Integer> onHttpCodes = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Exponential Backoff properties.
|
||||
*/
|
||||
@@ -128,4 +133,12 @@ public class SpringAiRetryProperties {
|
||||
this.onClientErrors = onClientErrors;
|
||||
}
|
||||
|
||||
public List<Integer> getOnHttpCodes() {
|
||||
return this.onHttpCodes;
|
||||
}
|
||||
|
||||
public void setOnHttpCodes(List<Integer> onHttpCodes) {
|
||||
this.onHttpCodes = onHttpCodes;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -37,10 +37,10 @@ public class SpringAiRetryPropertiesTests {
|
||||
var retryProperties = context.getBean(SpringAiRetryProperties.class);
|
||||
|
||||
assertThat(retryProperties.getMaxAttempts()).isEqualTo(10);
|
||||
assertThat(retryProperties.isOnClientErrors()).isFalse(); // do not retry
|
||||
// on 4xx
|
||||
// errors
|
||||
// do not retry on 4xx errors
|
||||
assertThat(retryProperties.isOnClientErrors()).isFalse();
|
||||
assertThat(retryProperties.getExcludeOnHttpCodes()).isEmpty();
|
||||
assertThat(retryProperties.getOnHttpCodes()).isEmpty();
|
||||
assertThat(retryProperties.getBackoff().getInitialInterval().toMillis()).isEqualTo(2000);
|
||||
assertThat(retryProperties.getBackoff().getMultiplier()).isEqualTo(5);
|
||||
assertThat(retryProperties.getBackoff().getMaxInterval().toMillis()).isEqualTo(3 * 60000);
|
||||
@@ -55,6 +55,7 @@ public class SpringAiRetryPropertiesTests {
|
||||
"spring.ai.retry.max-attempts=100",
|
||||
"spring.ai.retry.on-client-errors=false",
|
||||
"spring.ai.retry.exclude-on-http-codes=404,500",
|
||||
"spring.ai.retry.on-http-codes=429",
|
||||
"spring.ai.retry.backoff.initial-interval=1000",
|
||||
"spring.ai.retry.backoff.multiplier=2",
|
||||
"spring.ai.retry.backoff.max-interval=60000" )
|
||||
@@ -66,6 +67,7 @@ public class SpringAiRetryPropertiesTests {
|
||||
assertThat(retryProperties.getMaxAttempts()).isEqualTo(100);
|
||||
assertThat(retryProperties.isOnClientErrors()).isFalse();
|
||||
assertThat(retryProperties.getExcludeOnHttpCodes()).containsExactly(404, 500);
|
||||
assertThat(retryProperties.getOnHttpCodes()).containsExactly(429);
|
||||
assertThat(retryProperties.getBackoff().getInitialInterval().toMillis()).isEqualTo(1000);
|
||||
assertThat(retryProperties.getBackoff().getMultiplier()).isEqualTo(2);
|
||||
assertThat(retryProperties.getBackoff().getMaxInterval().toMillis()).isEqualTo(60000);
|
||||
|
||||
Reference in New Issue
Block a user