-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Retryer: replace an instance of Date with an epoch millisecond #2170
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
Changes from all commits
5289775
824dce9
e079e4e
fc09db3
cd24cc4
19be653
c391472
1690c29
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,14 +24,22 @@ | |
| */ | ||
| public class RetryableException extends FeignException { | ||
|
|
||
| private static final long serialVersionUID = 1L; | ||
| private static final long serialVersionUID = 2L; | ||
|
|
||
| private final Long retryAfter; | ||
| private final HttpMethod httpMethod; | ||
|
|
||
| /** | ||
| * @param retryAfter usually corresponds to the {@link feign.Util#RETRY_AFTER} header. | ||
| */ | ||
| public RetryableException(int status, String message, HttpMethod httpMethod, Throwable cause, | ||
| Long retryAfter, Request request) { | ||
| super(status, message, request, cause); | ||
| this.httpMethod = httpMethod; | ||
| this.retryAfter = retryAfter; | ||
| } | ||
|
|
||
| @Deprecated | ||
| public RetryableException(int status, String message, HttpMethod httpMethod, Throwable cause, | ||
| Date retryAfter, Request request) { | ||
| super(status, message, request, cause); | ||
|
Comment on lines
+42
to
45
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This constructor is marked as deprecated and still uses
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
@@ -42,6 +50,14 @@ public RetryableException(int status, String message, HttpMethod httpMethod, Thr | |
| /** | ||
| * @param retryAfter usually corresponds to the {@link feign.Util#RETRY_AFTER} header. | ||
| */ | ||
| public RetryableException(int status, String message, HttpMethod httpMethod, Long retryAfter, | ||
| Request request) { | ||
| super(status, message, request); | ||
| this.httpMethod = httpMethod; | ||
| this.retryAfter = retryAfter; | ||
| } | ||
|
|
||
| @Deprecated | ||
| public RetryableException(int status, String message, HttpMethod httpMethod, Date retryAfter, | ||
| Request request) { | ||
| super(status, message, request); | ||
|
Comment on lines
+60
to
63
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This constructor is marked as deprecated and still uses |
||
|
|
@@ -52,6 +68,15 @@ public RetryableException(int status, String message, HttpMethod httpMethod, Dat | |
| /** | ||
| * @param retryAfter usually corresponds to the {@link feign.Util#RETRY_AFTER} header. | ||
| */ | ||
| public RetryableException(int status, String message, HttpMethod httpMethod, Long retryAfter, | ||
| Request request, byte[] responseBody, | ||
| Map<String, Collection<String>> responseHeaders) { | ||
| super(status, message, request, responseBody, responseHeaders); | ||
| this.httpMethod = httpMethod; | ||
| this.retryAfter = retryAfter; | ||
| } | ||
|
|
||
| @Deprecated | ||
| public RetryableException(int status, String message, HttpMethod httpMethod, Date retryAfter, | ||
| Request request, byte[] responseBody, Map<String, Collection<String>> responseHeaders) { | ||
| super(status, message, request, responseBody, responseHeaders); | ||
|
Comment on lines
+79
to
82
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This constructor is marked as deprecated and still uses |
||
|
|
@@ -63,8 +88,8 @@ public RetryableException(int status, String message, HttpMethod httpMethod, Dat | |
| * Sometimes corresponds to the {@link feign.Util#RETRY_AFTER} header present in {@code 503} | ||
| * status. Other times parsed from an application-specific response. Null if unknown. | ||
| */ | ||
| public Date retryAfter() { | ||
| return retryAfter != null ? new Date(retryAfter) : null; | ||
| public Long retryAfter() { | ||
| return retryAfter; | ||
| } | ||
|
|
||
| public HttpMethod method() { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,16 +16,15 @@ | |
| import static feign.FeignException.errorStatus; | ||
| import static feign.Util.RETRY_AFTER; | ||
| import static feign.Util.checkNotNull; | ||
| import static java.util.Locale.US; | ||
| import static java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME; | ||
| import static java.util.concurrent.TimeUnit.SECONDS; | ||
| import feign.FeignException; | ||
| import feign.Response; | ||
| import feign.RetryableException; | ||
| import java.text.DateFormat; | ||
| import java.text.ParseException; | ||
| import java.text.SimpleDateFormat; | ||
| import java.time.ZonedDateTime; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's this available on java8? Nice |
||
| import java.time.format.DateTimeFormatter; | ||
| import java.time.format.DateTimeParseException; | ||
| import java.util.Collection; | ||
| import java.util.Date; | ||
| import java.util.Map; | ||
|
|
||
| /** | ||
|
|
@@ -103,7 +102,7 @@ public Default(Integer maxBodyBytesLength, Integer maxBodyCharsLength) { | |
| public Exception decode(String methodKey, Response response) { | ||
| FeignException exception = errorStatus(methodKey, response, maxBodyBytesLength, | ||
| maxBodyCharsLength); | ||
| Date retryAfter = retryAfterDecoder.apply(firstOrNull(response.headers(), RETRY_AFTER)); | ||
| Long retryAfter = retryAfterDecoder.apply(firstOrNull(response.headers(), RETRY_AFTER)); | ||
| if (retryAfter != null) { | ||
| return new RetryableException( | ||
| response.status(), | ||
|
|
@@ -125,48 +124,44 @@ private <T> T firstOrNull(Map<String, Collection<T>> map, String key) { | |
| } | ||
|
|
||
| /** | ||
| * Decodes a {@link feign.Util#RETRY_AFTER} header into an absolute date, if possible. <br> | ||
| * Decodes a {@link feign.Util#RETRY_AFTER} header into an epoch millisecond, if possible.<br> | ||
| * See <a href="https://tools.ietf.org/html/rfc2616#section-14.37">Retry-After format</a> | ||
| */ | ||
| static class RetryAfterDecoder { | ||
|
|
||
| static final DateFormat RFC822_FORMAT = | ||
| new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'", US); | ||
| private final DateFormat rfc822Format; | ||
| private final DateTimeFormatter dateTimeFormatter; | ||
|
|
||
| RetryAfterDecoder() { | ||
| this(RFC822_FORMAT); | ||
| this(RFC_1123_DATE_TIME); | ||
| } | ||
|
|
||
| RetryAfterDecoder(DateFormat rfc822Format) { | ||
| this.rfc822Format = checkNotNull(rfc822Format, "rfc822Format"); | ||
| RetryAfterDecoder(DateTimeFormatter dateTimeFormatter) { | ||
| this.dateTimeFormatter = checkNotNull(dateTimeFormatter, "dateTimeFormatter"); | ||
| } | ||
|
|
||
| protected long currentTimeMillis() { | ||
| return System.currentTimeMillis(); | ||
| } | ||
|
|
||
| /** | ||
| * returns a date that corresponds to the first time a request can be retried. | ||
| * returns an epoch millisecond that corresponds to the first time a request can be retried. | ||
| * | ||
| * @param retryAfter String in | ||
| * <a href="https://tools.ietf.org/html/rfc2616#section-14.37" >Retry-After format</a> | ||
| */ | ||
| public Date apply(String retryAfter) { | ||
| public Long apply(String retryAfter) { | ||
| if (retryAfter == null) { | ||
| return null; | ||
| } | ||
| if (retryAfter.matches("^[0-9]+\\.?0*$")) { | ||
| retryAfter = retryAfter.replaceAll("\\.0*$", ""); | ||
| long deltaMillis = SECONDS.toMillis(Long.parseLong(retryAfter)); | ||
| return new Date(currentTimeMillis() + deltaMillis); | ||
| return currentTimeMillis() + deltaMillis; | ||
| } | ||
| synchronized (rfc822Format) { | ||
| try { | ||
| return rfc822Format.parse(retryAfter); | ||
| } catch (ParseException ignored) { | ||
| return null; | ||
| } | ||
| try { | ||
| return ZonedDateTime.parse(retryAfter, dateTimeFormatter).toInstant().toEpochMilli(); | ||
| } catch (NullPointerException | DateTimeParseException ignored) { | ||
| return null; | ||
| } | ||
| } | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The change from
nulltofinal Long nonRetryable = null;doesn't seem to add any value. It just adds an extra line of code and a variable that is not necessary. The previous implementation was more concise and clear.