Skip to content

Add constructor to RetryableException for cases without retryAfter #2871

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 116 additions & 5 deletions core/src/main/java/feign/RetryableException.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,66 @@ public class RetryableException extends FeignException {
private final HttpMethod httpMethod;

/**
* @param retryAfter usually corresponds to the {@link feign.Util#RETRY_AFTER} header. If you
* don't want to retry, set null.
* Represents a non-retryable exception when Retry-After information is explicitly not provided.
* <p>
* Use this constructor when the server response does not include a Retry-After header
* or when retries are not expected.
*
* @param status the HTTP status code
* @param message the exception message
* @param httpMethod the HTTP method (GET, POST, etc.)
* @param request the original HTTP request
*/
public RetryableException(
int status,
String message,
HttpMethod httpMethod,
Request request) {
super(status, message, request);
this.httpMethod = httpMethod;
this.retryAfter = null;
}

/**
* Represents a non-retryable exception when Retry-After information is explicitly not provided.
* <p>
* Use this constructor when the server response does not include a Retry-After header
* or when retries are not expected.
*
* @param status the HTTP status code
* @param message the exception message
* @param httpMethod the HTTP method (GET, POST, etc.)
* @param cause the underlying cause of the exception
* @param request the original HTTP request
*/
public RetryableException(
int status,
String message,
HttpMethod httpMethod,
Throwable cause,
Request request) {
super(status, message, request, cause);
this.httpMethod = httpMethod;
this.retryAfter = null;
}

/**
* Represents a retryable exception when Retry-After information is available.
* <p>
* Use this constructor when the server response includes a Retry-After header
* specifying the delay in milliseconds before retrying.
* <p>
* If {@code retryAfter} is {@code null}, prefer using
* {@link #RetryableException(int, String, HttpMethod, Throwable, Request)} instead.
*
* @param status the HTTP status code
* @param message the exception message
* @param httpMethod the HTTP method (GET, POST, etc.)
* @param cause the underlying cause of the exception
* @param retryAfter the retry delay in milliseconds
* retryAfter usually corresponds to the {@link feign.Util#RETRY_AFTER} header. If you
* don't want to retry, use {@link #RetryableException(int, String, HttpMethod, Throwable, Request)}.
* @param request the original HTTP request
*/
public RetryableException(
int status,
Expand All @@ -47,6 +105,17 @@ public RetryableException(
this.retryAfter = retryAfter;
}

/**
* @deprecated Use {@link #RetryableException(int, String, HttpMethod, Throwable, Long, Request)}
* instead. This constructor uses {@link Date} for retryAfter, which has been replaced by {@link Long}.
*
* @param status the HTTP status code
* @param message the exception message
* @param httpMethod the HTTP method (GET, POST, etc.)
* @param cause the underlying cause of the exception
* @param retryAfter the retry-after time as a {@link Date}
* @param request the original HTTP request
*/
@Deprecated
public RetryableException(
int status,
Expand All @@ -61,8 +130,17 @@ public RetryableException(
}

/**
* @param retryAfter usually corresponds to the {@link feign.Util#RETRY_AFTER} header. If you
* don't want to retry, set null.
* Represents a retryable exception when Retry-After information is available.
* <p>
* Use this constructor when the server response includes a Retry-After header.
*
* @param status the HTTP status code
* @param message the exception message
* @param httpMethod the HTTP method (GET, POST, etc.)
* @param retryAfter the retry delay in milliseconds
* retryAfter usually corresponds to the {@link feign.Util#RETRY_AFTER} header. If you
* don't want to retry, use {@link #RetryableException(int, String, HttpMethod, Request)}
* @param request the original HTTP request
*/
public RetryableException(
int status, String message, HttpMethod httpMethod, Long retryAfter, Request request) {
Expand All @@ -71,6 +149,16 @@ public RetryableException(
this.retryAfter = retryAfter;
}

/**
* @deprecated Use {@link #RetryableException(int, String, HttpMethod, Long, Request)}
* instead. This constructor uses {@link Date} for retryAfter, which has been replaced by {@link Long}.
*
* @param status the HTTP status code
* @param message the exception message
* @param httpMethod the HTTP method (GET, POST, etc.)
* @param retryAfter the retry-after time as a {@link Date}
* @param request the original HTTP request
*/
@Deprecated
public RetryableException(
int status, String message, HttpMethod httpMethod, Date retryAfter, Request request) {
Expand All @@ -80,7 +168,18 @@ public RetryableException(
}

/**
* @param retryAfter usually corresponds to the {@link feign.Util#RETRY_AFTER} header.
* Represents a retryable exception with response body and headers.
* <p>
* Use this constructor when handling HTTP responses that include Retry-After information.
*
* @param status the HTTP status code
* @param message the exception message
* @param httpMethod the HTTP method (GET, POST, etc.)
* @param retryAfter the retry delay in milliseconds
* retryAfter usually corresponds to the {@link feign.Util#RETRY_AFTER} header.
* @param request the original HTTP request
* @param responseBody the HTTP response body
* @param responseHeaders the HTTP response headers
*/
public RetryableException(
int status,
Expand All @@ -95,6 +194,18 @@ public RetryableException(
this.retryAfter = retryAfter;
}

/**
* @deprecated Use {@link #RetryableException(int, String, HttpMethod, Long, Request, byte[], Map)}
* instead. This constructor uses {@link Date} for retryAfter, which has been replaced by {@link Long}.
*
* @param status the HTTP status code
* @param message the exception message
* @param httpMethod the HTTP method (GET, POST, etc.)
* @param retryAfter the retry-after time as a {@link Date}
* @param request the original HTTP request
* @param responseBody the HTTP response body
* @param responseHeaders the HTTP response headers
*/
@Deprecated
public RetryableException(
int status,
Expand Down
25 changes: 25 additions & 0 deletions core/src/test/java/feign/RetryerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,29 @@ void defaultRetryerFailsOnInterruptedException() {
assertThat(e).as("Unexpected exception found").isEqualTo(expected);
}
}

@Test
void canCreateRetryableExceptionWithoutRetryAfter() {
RetryableException exception = new RetryableException(500, "Internal Server Error", Request.HttpMethod.GET, REQUEST);

assertThat(exception.status()).isEqualTo(500);
assertThat(exception.getMessage()).contains("Internal Server Error");
assertThat(exception.method()).isEqualTo(Request.HttpMethod.GET);
assertThat(exception.retryAfter()).isNull();
}

@Test
void canCreateRetryableExceptionWithoutRetryAfterAndWithCause() {
Throwable cause = new IllegalArgumentException("Illegal argument exception");

try {
throw new RetryableException(500, "Internal Server Error", Request.HttpMethod.GET, cause, REQUEST);
} catch (RetryableException exception) {
assertThat(exception.status()).isEqualTo(500);
assertThat(exception.getMessage()).contains("Internal Server Error");
assertThat(exception.method()).isEqualTo(Request.HttpMethod.GET);
assertThat(exception.retryAfter()).isNull();
assertThat(exception.getCause()).isEqualTo(cause);
}
}
}