Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
S
spring-cloud-netflix
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
openSource
spring-cloud-netflix
Commits
8dcf5440
Commit
8dcf5440
authored
Apr 05, 2017
by
Ryan Baxter
Committed by
GitHub
Apr 05, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1836 from ryanjbaxter/response-code-retry
Add the ability for ribbon clients to specify response status codes they would like to retry
parents
98cbf2f4
6290859f
Show whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
448 additions
and
75 deletions
+448
-75
spring-cloud-netflix.adoc
docs/src/main/asciidoc/spring-cloud-netflix.adoc
+16
-0
RetryableFeignLoadBalancer.java
...loud/netflix/feign/ribbon/RetryableFeignLoadBalancer.java
+5
-1
RibbonAutoConfiguration.java
...amework/cloud/netflix/ribbon/RibbonAutoConfiguration.java
+2
-0
RibbonLoadBalancedRetryPolicy.java
...k/cloud/netflix/ribbon/RibbonLoadBalancedRetryPolicy.java
+123
-0
RibbonLoadBalancedRetryPolicyFactory.java
.../netflix/ribbon/RibbonLoadBalancedRetryPolicyFactory.java
+4
-57
RetryableRibbonLoadBalancingHttpClient.java
...ribbon/apache/RetryableRibbonLoadBalancingHttpClient.java
+10
-4
RetryableOkHttpLoadBalancingClient.java
...lix/ribbon/okhttp/RetryableOkHttpLoadBalancingClient.java
+10
-6
RetryableStatusCodeException.java
.../netflix/ribbon/support/RetryableStatusCodeException.java
+34
-0
RetryableFeignLoadBalancerTest.java
.../netflix/feign/ribbon/RetryableFeignLoadBalancerTest.java
+47
-0
RibbonLoadBalancedRetryPolicyFactoryTest.java
...flix/ribbon/RibbonLoadBalancedRetryPolicyFactoryTest.java
+30
-0
RibbonLoadBalancingHttpClientTests.java
...lix/ribbon/apache/RibbonLoadBalancingHttpClientTests.java
+59
-6
RetryableStatusCodeExceptionTest.java
...flix/ribbon/support/RetryableStatusCodeExceptionTest.java
+37
-0
HttpClientRibbonRetryIntegrationTests.java
...s/route/apache/HttpClientRibbonRetryIntegrationTests.java
+2
-1
OkHttpRibbonRetryIntegrationTests.java
...lters/route/okhttp/OkHttpRibbonRetryIntegrationTests.java
+1
-0
RibbonRetryIntegrationTestBase.java
...filters/route/support/RibbonRetryIntegrationTestBase.java
+68
-0
No files found.
docs/src/main/asciidoc/spring-cloud-netflix.adoc
View file @
8dcf5440
...
...
@@ -2461,6 +2461,22 @@ certain Ribbon properties. The properties you can use are
`
client
.
ribbon
.
OkToRetryOnAllOperations
`.
See
the
https
://
github
.
com
/
Netflix
/
ribbon
/
wiki
/
Getting
-
Started
#
the
-
properties
-
file
-
sample
-
clientproperties
[
Ribbon
documentation
]
for
a
description
of
what
there
properties
do
.
In
addition
you
may
want
to
retry
requests
when
certain
status
codes
are
returned
in
the
response
.
You
can
list
the
response
codes
you
would
like
the
Ribbon
client
to
retry
using
the
property
`
clientName
.
ribbon
.
retryableStatusCodes
`.
For
example
[
source
,
yaml
]
----
clientName
:
ribbon
:
retryableStatusCodes
:
404
,
502
----
You
can
also
create
a
bean
of
type
`
LoadBalancedRetryPolicy
`
and
implement
the
`
retryableStatusCode
`
method
to
determine
whether
you
want
to
retry
a
request
given
the
status
code
.
====
Zuul
You
can
turn
off
Zuul
's retry functionality by setting `zuul.retryable` to `false`. You
...
...
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/ribbon/RetryableFeignLoadBalancer.java
View file @
8dcf5440
...
...
@@ -29,6 +29,7 @@ import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryPolicyFact
import
org.springframework.cloud.client.loadbalancer.ServiceInstanceChooser
;
import
org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient
;
import
org.springframework.cloud.netflix.ribbon.ServerIntrospector
;
import
org.springframework.cloud.netflix.ribbon.support.RetryableStatusCodeException
;
import
org.springframework.retry.RetryCallback
;
import
org.springframework.retry.RetryContext
;
import
org.springframework.retry.policy.NeverRetryPolicy
;
...
...
@@ -69,7 +70,7 @@ public class RetryableFeignLoadBalancer extends FeignLoadBalancer implements Ser
else
{
options
=
new
Request
.
Options
(
this
.
connectTimeout
,
this
.
readTimeout
);
}
LoadBalancedRetryPolicy
retryPolicy
=
loadBalancedRetryPolicyFactory
.
create
(
this
.
getClientName
(),
this
);
final
LoadBalancedRetryPolicy
retryPolicy
=
loadBalancedRetryPolicyFactory
.
create
(
this
.
getClientName
(),
this
);
RetryTemplate
retryTemplate
=
new
RetryTemplate
();
retryTemplate
.
setRetryPolicy
(
retryPolicy
==
null
?
new
NeverRetryPolicy
()
:
new
FeignRetryPolicy
(
request
.
toHttpRequest
(),
retryPolicy
,
this
,
this
.
getClientName
()));
...
...
@@ -89,6 +90,9 @@ public class RetryableFeignLoadBalancer extends FeignLoadBalancer implements Ser
feignRequest
=
request
.
toRequest
();
}
Response
response
=
request
.
client
().
execute
(
feignRequest
,
options
);
if
(
retryPolicy
.
retryableStatusCode
(
response
.
status
()))
{
throw
new
RetryableStatusCodeException
(
RetryableFeignLoadBalancer
.
this
.
getClientName
(),
response
.
status
());
}
return
new
RibbonResponse
(
request
.
getUri
(),
response
);
}
});
...
...
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonAutoConfiguration.java
View file @
8dcf5440
...
...
@@ -90,12 +90,14 @@ public class RibbonAutoConfiguration {
@Bean
@ConditionalOnClass
(
name
=
"org.springframework.retry.support.RetryTemplate"
)
@ConditionalOnMissingBean
public
LoadBalancedRetryPolicyFactory
loadBalancedRetryPolicyFactory
(
SpringClientFactory
clientFactory
)
{
return
new
RibbonLoadBalancedRetryPolicyFactory
(
clientFactory
);
}
@Bean
@ConditionalOnMissingClass
(
value
=
"org.springframework.retry.support.RetryTemplate"
)
@ConditionalOnMissingBean
public
LoadBalancedRetryPolicyFactory
neverRetryPolicyFactory
()
{
return
new
LoadBalancedRetryPolicyFactory
.
NeverRetryFactory
();
}
...
...
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonLoadBalancedRetryPolicy.java
0 → 100644
View file @
8dcf5440
/*
*
* * Copyright 2013-2016 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * http://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
package
org
.
springframework
.
cloud
.
netflix
.
ribbon
;
import
java.util.ArrayList
;
import
java.util.List
;
import
org.springframework.cloud.client.loadbalancer.LoadBalancedRetryContext
;
import
org.springframework.cloud.client.loadbalancer.LoadBalancedRetryPolicy
;
import
org.springframework.cloud.client.loadbalancer.ServiceInstanceChooser
;
import
org.springframework.core.env.Environment
;
import
org.springframework.http.HttpMethod
;
import
org.springframework.util.StringUtils
;
import
com.netflix.client.config.CommonClientConfigKey
;
import
com.netflix.client.config.IClientConfig
;
import
com.netflix.client.config.IClientConfigKey
;
/**
* {@link LoadBalancedRetryPolicy} for Ribbon clients.
* @author Ryan Baxter
*/
public
class
RibbonLoadBalancedRetryPolicy
implements
LoadBalancedRetryPolicy
{
public
static
final
IClientConfigKey
<
String
>
RETRYABLE_STATUS_CODES
=
new
CommonClientConfigKey
<
String
>(
"retryableStatusCodes"
)
{};
private
int
sameServerCount
=
0
;
private
int
nextServerCount
=
0
;
private
String
serviceId
;
private
RibbonLoadBalancerContext
lbContext
;
private
ServiceInstanceChooser
loadBalanceChooser
;
List
<
Integer
>
retryableStatusCodes
=
new
ArrayList
<>();
public
RibbonLoadBalancedRetryPolicy
(
String
serviceId
,
RibbonLoadBalancerContext
context
,
ServiceInstanceChooser
loadBalanceChooser
)
{
this
.
serviceId
=
serviceId
;
this
.
lbContext
=
context
;
this
.
loadBalanceChooser
=
loadBalanceChooser
;
}
public
RibbonLoadBalancedRetryPolicy
(
String
serviceId
,
RibbonLoadBalancerContext
context
,
ServiceInstanceChooser
loadBalanceChooser
,
IClientConfig
clientConfig
)
{
this
.
serviceId
=
serviceId
;
this
.
lbContext
=
context
;
this
.
loadBalanceChooser
=
loadBalanceChooser
;
String
retryableStatusCodesProp
=
clientConfig
.
getPropertyAsString
(
RETRYABLE_STATUS_CODES
,
""
);
String
[]
retryableStatusCodesArray
=
retryableStatusCodesProp
.
split
(
","
);
for
(
String
code
:
retryableStatusCodesArray
)
{
if
(!
StringUtils
.
isEmpty
(
code
))
{
try
{
retryableStatusCodes
.
add
(
Integer
.
valueOf
(
code
));
}
catch
(
NumberFormatException
e
)
{
//TODO log
}
}
}
}
public
boolean
canRetry
(
LoadBalancedRetryContext
context
)
{
HttpMethod
method
=
context
.
getRequest
().
getMethod
();
return
HttpMethod
.
GET
==
method
||
lbContext
.
isOkToRetryOnAllOperations
();
}
@Override
public
boolean
canRetrySameServer
(
LoadBalancedRetryContext
context
)
{
return
sameServerCount
<
lbContext
.
getRetryHandler
().
getMaxRetriesOnSameServer
()
&&
canRetry
(
context
);
}
@Override
public
boolean
canRetryNextServer
(
LoadBalancedRetryContext
context
)
{
//this will be called after a failure occurs and we increment the counter
//so we check that the count is less than or equals to too make sure
//we try the next server the right number of times
return
nextServerCount
<=
lbContext
.
getRetryHandler
().
getMaxRetriesOnNextServer
()
&&
canRetry
(
context
);
}
@Override
public
void
close
(
LoadBalancedRetryContext
context
)
{
}
@Override
public
void
registerThrowable
(
LoadBalancedRetryContext
context
,
Throwable
throwable
)
{
//Check if we need to ask the load balancer for a new server.
//Do this before we increment the counters because the first call to this method
//is not a retry it is just an initial failure.
if
(!
canRetrySameServer
(
context
)
&&
canRetryNextServer
(
context
))
{
context
.
setServiceInstance
(
loadBalanceChooser
.
choose
(
serviceId
));
}
//This method is called regardless of whether we are retrying or making the first request.
//Since we do not count the initial request in the retry count we don't reset the counter
//until we actually equal the same server count limit. This will allow us to make the initial
//request plus the right number of retries.
if
(
sameServerCount
>=
lbContext
.
getRetryHandler
().
getMaxRetriesOnSameServer
()
&&
canRetry
(
context
))
{
//reset same server since we are moving to a new server
sameServerCount
=
0
;
nextServerCount
++;
if
(!
canRetryNextServer
(
context
))
{
context
.
setExhaustedOnly
();
}
}
else
{
sameServerCount
++;
}
}
@Override
public
boolean
retryableStatusCode
(
int
statusCode
)
{
return
retryableStatusCodes
.
contains
(
statusCode
);
}
}
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonLoadBalancedRetryPolicyFactory.java
View file @
8dcf5440
...
...
@@ -15,12 +15,9 @@
*/
package
org
.
springframework
.
cloud
.
netflix
.
ribbon
;
import
org.springframework.cloud.client.ServiceInstance
;
import
org.springframework.cloud.client.loadbalancer.LoadBalancedRetryContext
;
import
org.springframework.cloud.client.loadbalancer.LoadBalancedRetryPolicy
;
import
org.springframework.cloud.client.loadbalancer.LoadBalancedRetryPolicyFactory
;
import
org.springframework.cloud.client.loadbalancer.ServiceInstanceChooser
;
import
org.springframework.http.HttpMethod
;
/**
* @author Ryan Baxter
...
...
@@ -34,60 +31,10 @@ public class RibbonLoadBalancedRetryPolicyFactory implements LoadBalancedRetryPo
}
@Override
public
LoadBalancedRetryPolicy
create
(
final
String
serviceId
,
final
ServiceInstanceChooser
loadBalanceChooser
)
{
final
RibbonLoadBalancerContext
lbContext
=
this
.
clientFactory
public
LoadBalancedRetryPolicy
create
(
String
serviceId
,
ServiceInstanceChooser
loadBalanceChooser
)
{
RibbonLoadBalancerContext
lbContext
=
this
.
clientFactory
.
getLoadBalancerContext
(
serviceId
);
return
new
LoadBalancedRetryPolicy
()
{
private
int
sameServerCount
=
0
;
private
int
nextServerCount
=
0
;
private
ServiceInstance
lastServiceInstance
=
null
;
public
boolean
canRetry
(
LoadBalancedRetryContext
context
)
{
HttpMethod
method
=
context
.
getRequest
().
getMethod
();
return
HttpMethod
.
GET
==
method
||
lbContext
.
isOkToRetryOnAllOperations
();
}
@Override
public
boolean
canRetrySameServer
(
LoadBalancedRetryContext
context
)
{
return
sameServerCount
<
lbContext
.
getRetryHandler
().
getMaxRetriesOnSameServer
()
&&
canRetry
(
context
);
}
@Override
public
boolean
canRetryNextServer
(
LoadBalancedRetryContext
context
)
{
//this will be called after a failure occurs and we increment the counter
//so we check that the count is less than or equals to too make sure
//we try the next server the right number of times
return
nextServerCount
<=
lbContext
.
getRetryHandler
().
getMaxRetriesOnNextServer
()
&&
canRetry
(
context
);
}
@Override
public
void
close
(
LoadBalancedRetryContext
context
)
{
}
@Override
public
void
registerThrowable
(
LoadBalancedRetryContext
context
,
Throwable
throwable
)
{
//Check if we need to ask the load balancer for a new server.
//Do this before we increment the counters because the first call to this method
//is not a retry it is just an initial failure.
if
(!
canRetrySameServer
(
context
)
&&
canRetryNextServer
(
context
))
{
context
.
setServiceInstance
(
loadBalanceChooser
.
choose
(
serviceId
));
}
//This method is called regardless of whether we are retrying or making the first request.
//Since we do not count the initial request in the retry count we don't reset the counter
//until we actually equal the same server count limit. This will allow us to make the initial
//request plus the right number of retries.
if
(
sameServerCount
>=
lbContext
.
getRetryHandler
().
getMaxRetriesOnSameServer
()
&&
canRetry
(
context
))
{
//reset same server since we are moving to a new server
sameServerCount
=
0
;
nextServerCount
++;
if
(!
canRetryNextServer
(
context
))
{
context
.
setExhaustedOnly
();
}
}
else
{
sameServerCount
++;
}
}
};
return
new
RibbonLoadBalancedRetryPolicy
(
serviceId
,
lbContext
,
loadBalanceChooser
,
clientFactory
.
getClientConfig
(
serviceId
));
}
}
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/apache/RetryableRibbonLoadBalancingHttpClient.java
View file @
8dcf5440
...
...
@@ -29,6 +29,7 @@ import org.springframework.cloud.client.loadbalancer.ServiceInstanceChooser;
import
org.springframework.cloud.netflix.feign.ribbon.FeignRetryPolicy
;
import
org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient
;
import
org.springframework.cloud.netflix.ribbon.ServerIntrospector
;
import
org.springframework.cloud.netflix.ribbon.support.RetryableStatusCodeException
;
import
org.springframework.http.HttpRequest
;
import
org.springframework.retry.RetryCallback
;
import
org.springframework.retry.RetryContext
;
...
...
@@ -65,7 +66,8 @@ public class RetryableRibbonLoadBalancingHttpClient extends RibbonLoadBalancingH
CommonClientConfigKey
.
FollowRedirects
,
this
.
followRedirects
));
final
RequestConfig
requestConfig
=
builder
.
build
();
return
this
.
executeWithRetry
(
request
,
new
RetryCallback
()
{
final
LoadBalancedRetryPolicy
retryPolicy
=
loadBalancedRetryPolicyFactory
.
create
(
this
.
getClientName
(),
this
);
RetryCallback
retryCallback
=
new
RetryCallback
()
{
@Override
public
RibbonApacheHttpResponse
doWithRetry
(
RetryContext
context
)
throws
Exception
{
//on retries the policy will choose the server and set it in the context
...
...
@@ -88,13 +90,17 @@ public class RetryableRibbonLoadBalancingHttpClient extends RibbonLoadBalancingH
}
HttpUriRequest
httpUriRequest
=
newRequest
.
toRequest
(
requestConfig
);
final
HttpResponse
httpResponse
=
RetryableRibbonLoadBalancingHttpClient
.
this
.
delegate
.
execute
(
httpUriRequest
);
if
(
retryPolicy
.
retryableStatusCode
(
httpResponse
.
getStatusLine
().
getStatusCode
()))
{
throw
new
RetryableStatusCodeException
(
RetryableRibbonLoadBalancingHttpClient
.
this
.
clientName
,
httpResponse
.
getStatusLine
().
getStatusCode
());
}
return
new
RibbonApacheHttpResponse
(
httpResponse
,
httpUriRequest
.
getURI
());
}
});
};
return
this
.
executeWithRetry
(
request
,
retryPolicy
,
retryCallback
);
}
private
RibbonApacheHttpResponse
executeWithRetry
(
RibbonApacheHttpRequest
request
,
RetryCallback
<
RibbonApacheHttpResponse
,
IOException
>
callback
)
throws
Exception
{
LoadBalancedRetryPolicy
retryPolicy
=
loadBalancedRetryPolicyFactory
.
create
(
this
.
getClientName
(),
this
);
private
RibbonApacheHttpResponse
executeWithRetry
(
RibbonApacheHttpRequest
request
,
LoadBalancedRetryPolicy
retryPolicy
,
RetryCallback
<
RibbonApacheHttpResponse
,
IOException
>
callback
)
throws
Exception
{
RetryTemplate
retryTemplate
=
new
RetryTemplate
();
boolean
retryable
=
request
.
getContext
()
==
null
?
true
:
BooleanUtils
.
toBooleanDefaultIfNull
(
request
.
getContext
().
getRetryable
(),
true
);
...
...
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/okhttp/RetryableOkHttpLoadBalancingClient.java
View file @
8dcf5440
...
...
@@ -19,7 +19,6 @@ import okhttp3.OkHttpClient;
import
okhttp3.Request
;
import
okhttp3.Response
;
import
java.io.IOException
;
import
java.net.URI
;
import
org.apache.commons.lang.BooleanUtils
;
import
org.springframework.cloud.client.ServiceInstance
;
...
...
@@ -30,6 +29,7 @@ import org.springframework.cloud.client.loadbalancer.ServiceInstanceChooser;
import
org.springframework.cloud.netflix.feign.ribbon.FeignRetryPolicy
;
import
org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient
;
import
org.springframework.cloud.netflix.ribbon.ServerIntrospector
;
import
org.springframework.cloud.netflix.ribbon.support.RetryableStatusCodeException
;
import
org.springframework.http.HttpRequest
;
import
org.springframework.retry.RetryCallback
;
import
org.springframework.retry.RetryContext
;
...
...
@@ -55,10 +55,9 @@ public class RetryableOkHttpLoadBalancingClient extends OkHttpLoadBalancingClien
this
.
loadBalancedRetryPolicyFactory
=
loadBalancedRetryPolicyFactory
;
}
private
OkHttpRibbonResponse
executeWithRetry
(
OkHttpRibbonRequest
request
,
RetryCallback
<
OkHttpRibbonResponse
,
IO
Exception
>
callback
)
private
OkHttpRibbonResponse
executeWithRetry
(
OkHttpRibbonRequest
request
,
LoadBalancedRetryPolicy
retryPolicy
,
RetryCallback
<
OkHttpRibbonResponse
,
Exception
>
callback
)
throws
Exception
{
LoadBalancedRetryPolicy
retryPolicy
=
loadBalancedRetryPolicyFactory
.
create
(
this
.
getClientName
(),
this
);
RetryTemplate
retryTemplate
=
new
RetryTemplate
();
boolean
retryable
=
request
.
getContext
()
==
null
?
true
:
BooleanUtils
.
toBooleanDefaultIfNull
(
request
.
getContext
().
getRetryable
(),
true
);
...
...
@@ -70,7 +69,8 @@ public class RetryableOkHttpLoadBalancingClient extends OkHttpLoadBalancingClien
@Override
public
OkHttpRibbonResponse
execute
(
final
OkHttpRibbonRequest
ribbonRequest
,
final
IClientConfig
configOverride
)
throws
Exception
{
return
this
.
executeWithRetry
(
ribbonRequest
,
new
RetryCallback
()
{
final
LoadBalancedRetryPolicy
retryPolicy
=
loadBalancedRetryPolicyFactory
.
create
(
this
.
getClientName
(),
this
);
RetryCallback
<
OkHttpRibbonResponse
,
Exception
>
retryCallback
=
new
RetryCallback
<
OkHttpRibbonResponse
,
Exception
>()
{
@Override
public
OkHttpRibbonResponse
doWithRetry
(
RetryContext
context
)
throws
Exception
{
//on retries the policy will choose the server and set it in the context
...
...
@@ -95,9 +95,13 @@ public class RetryableOkHttpLoadBalancingClient extends OkHttpLoadBalancingClien
final
Request
request
=
newRequest
.
toRequest
();
Response
response
=
httpClient
.
newCall
(
request
).
execute
();
if
(
retryPolicy
.
retryableStatusCode
(
response
.
code
()))
{
throw
new
RetryableStatusCodeException
(
RetryableOkHttpLoadBalancingClient
.
this
.
clientName
,
response
.
code
());
}
return
new
OkHttpRibbonResponse
(
response
,
newRequest
.
getUri
());
}
});
};
return
this
.
executeWithRetry
(
ribbonRequest
,
retryPolicy
,
retryCallback
);
}
@Override
...
...
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/support/RetryableStatusCodeException.java
0 → 100644
View file @
8dcf5440
/*
*
* * Copyright 2013-2016 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * http://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
package
org
.
springframework
.
cloud
.
netflix
.
ribbon
.
support
;
import
java.io.IOException
;
/**
* Exception to be thrown when the status code is deemed to be retryable.
* @author Ryan Baxter
*/
public
class
RetryableStatusCodeException
extends
IOException
{
private
static
final
String
MESSAGE
=
"Service %s returned a status code of %d"
;
public
RetryableStatusCodeException
(
String
serviceId
,
int
statusCode
)
{
super
(
String
.
format
(
MESSAGE
,
serviceId
,
statusCode
));
}
}
spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/ribbon/RetryableFeignLoadBalancerTest.java
View file @
8dcf5440
...
...
@@ -37,6 +37,7 @@ import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryPolicy;
import
org.springframework.cloud.client.loadbalancer.LoadBalancedRetryPolicyFactory
;
import
org.springframework.cloud.client.loadbalancer.ServiceInstanceChooser
;
import
org.springframework.cloud.netflix.ribbon.DefaultServerIntrospector
;
import
org.springframework.cloud.netflix.ribbon.RibbonLoadBalancedRetryPolicy
;
import
org.springframework.cloud.netflix.ribbon.RibbonLoadBalancedRetryPolicyFactory
;
import
org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerContext
;
import
org.springframework.cloud.netflix.ribbon.ServerIntrospector
;
...
...
@@ -44,6 +45,7 @@ import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import
org.springframework.http.HttpRequest
;
import
com.netflix.client.RequestSpecificRetryHandler
;
import
com.netflix.client.config.CommonClientConfigKey
;
import
com.netflix.client.config.IClientConfig
;
import
com.netflix.loadbalancer.ILoadBalancer
;
import
com.netflix.loadbalancer.Server
;
...
...
@@ -60,6 +62,7 @@ import static org.hamcrest.Matchers.instanceOf;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
mockito
.
Matchers
.
any
;
import
static
org
.
mockito
.
Matchers
.
anyBoolean
;
import
static
org
.
mockito
.
Matchers
.
anyInt
;
import
static
org
.
mockito
.
Matchers
.
eq
;
import
static
org
.
mockito
.
Mockito
.
doReturn
;
import
static
org
.
mockito
.
Mockito
.
doThrow
;
...
...
@@ -98,6 +101,14 @@ public class RetryableFeignLoadBalancerTest {
RibbonLoadBalancerContext
lbContext
=
new
RibbonLoadBalancerContext
(
lb
,
config
);
SpringClientFactory
clientFactory
=
mock
(
SpringClientFactory
.
class
);
doReturn
(
lbContext
).
when
(
clientFactory
).
getLoadBalancerContext
(
any
(
String
.
class
));
IClientConfig
config
=
mock
(
IClientConfig
.
class
);
doReturn
(
1
).
when
(
config
).
get
(
eq
(
CommonClientConfigKey
.
MaxAutoRetries
),
anyInt
());
doReturn
(
1
).
when
(
config
).
get
(
eq
(
CommonClientConfigKey
.
MaxAutoRetriesNextServer
),
anyInt
());
doReturn
(
true
).
when
(
config
).
get
(
eq
(
CommonClientConfigKey
.
OkToRetryOnAllOperations
),
eq
(
false
));
doReturn
(
defaultConnectTimeout
).
when
(
config
).
get
(
eq
(
CommonClientConfigKey
.
ConnectTimeout
));
doReturn
(
defaultReadTimeout
).
when
(
config
).
get
(
eq
(
CommonClientConfigKey
.
ReadTimeout
));
doReturn
(
"404,502,foo, ,"
).
when
(
config
).
getPropertyAsString
(
eq
(
RibbonLoadBalancedRetryPolicy
.
RETRYABLE_STATUS_CODES
),
eq
(
""
));
doReturn
(
config
).
when
(
clientFactory
).
getClientConfig
(
eq
(
"default"
));
RibbonLoadBalancedRetryPolicyFactory
loadBalancedRetryPolicyFactory
=
new
RibbonLoadBalancedRetryPolicyFactory
(
clientFactory
);
HttpRequest
springRequest
=
mock
(
HttpRequest
.
class
);
Request
feignRequest
=
Request
.
create
(
"GET"
,
"http://foo"
,
new
HashMap
<
String
,
Collection
<
String
>>(),
...
...
@@ -139,6 +150,14 @@ public class RetryableFeignLoadBalancerTest {
public
void
executeRetry
()
throws
Exception
{
RibbonLoadBalancerContext
lbContext
=
new
RibbonLoadBalancerContext
(
lb
,
config
);
SpringClientFactory
clientFactory
=
mock
(
SpringClientFactory
.
class
);
IClientConfig
config
=
mock
(
IClientConfig
.
class
);
doReturn
(
1
).
when
(
config
).
get
(
eq
(
CommonClientConfigKey
.
MaxAutoRetries
),
anyInt
());
doReturn
(
1
).
when
(
config
).
get
(
eq
(
CommonClientConfigKey
.
MaxAutoRetriesNextServer
),
anyInt
());
doReturn
(
true
).
when
(
config
).
get
(
eq
(
CommonClientConfigKey
.
OkToRetryOnAllOperations
),
eq
(
false
));
doReturn
(
defaultConnectTimeout
).
when
(
config
).
get
(
eq
(
CommonClientConfigKey
.
ConnectTimeout
));
doReturn
(
defaultReadTimeout
).
when
(
config
).
get
(
eq
(
CommonClientConfigKey
.
ReadTimeout
));
doReturn
(
""
).
when
(
config
).
getPropertyAsString
(
eq
(
RibbonLoadBalancedRetryPolicy
.
RETRYABLE_STATUS_CODES
),
eq
(
""
));
doReturn
(
config
).
when
(
clientFactory
).
getClientConfig
(
eq
(
"default"
));
doReturn
(
lbContext
).
when
(
clientFactory
).
getLoadBalancerContext
(
any
(
String
.
class
));
RibbonLoadBalancedRetryPolicyFactory
loadBalancedRetryPolicyFactory
=
new
RibbonLoadBalancedRetryPolicyFactory
(
clientFactory
);
HttpRequest
springRequest
=
mock
(
HttpRequest
.
class
);
...
...
@@ -155,6 +174,34 @@ public class RetryableFeignLoadBalancerTest {
}
@Test
public
void
executeRetryOnStatusCode
()
throws
Exception
{
RibbonLoadBalancerContext
lbContext
=
new
RibbonLoadBalancerContext
(
lb
,
config
);
SpringClientFactory
clientFactory
=
mock
(
SpringClientFactory
.
class
);
IClientConfig
config
=
mock
(
IClientConfig
.
class
);
doReturn
(
1
).
when
(
config
).
get
(
eq
(
CommonClientConfigKey
.
MaxAutoRetries
),
anyInt
());
doReturn
(
1
).
when
(
config
).
get
(
eq
(
CommonClientConfigKey
.
MaxAutoRetriesNextServer
),
anyInt
());
doReturn
(
true
).
when
(
config
).
get
(
eq
(
CommonClientConfigKey
.
OkToRetryOnAllOperations
),
eq
(
false
));
doReturn
(
defaultConnectTimeout
).
when
(
config
).
get
(
eq
(
CommonClientConfigKey
.
ConnectTimeout
));
doReturn
(
defaultReadTimeout
).
when
(
config
).
get
(
eq
(
CommonClientConfigKey
.
ReadTimeout
));
doReturn
(
"404"
).
when
(
config
).
getPropertyAsString
(
eq
(
RibbonLoadBalancedRetryPolicy
.
RETRYABLE_STATUS_CODES
),
eq
(
""
));
doReturn
(
config
).
when
(
clientFactory
).
getClientConfig
(
eq
(
"default"
));
doReturn
(
lbContext
).
when
(
clientFactory
).
getLoadBalancerContext
(
any
(
String
.
class
));
RibbonLoadBalancedRetryPolicyFactory
loadBalancedRetryPolicyFactory
=
new
RibbonLoadBalancedRetryPolicyFactory
(
clientFactory
);
HttpRequest
springRequest
=
mock
(
HttpRequest
.
class
);
Request
feignRequest
=
Request
.
create
(
"GET"
,
"http://foo"
,
new
HashMap
<
String
,
Collection
<
String
>>(),
new
byte
[]{},
StandardCharsets
.
UTF_8
);
Client
client
=
mock
(
Client
.
class
);
FeignLoadBalancer
.
RibbonRequest
request
=
new
FeignLoadBalancer
.
RibbonRequest
(
client
,
feignRequest
,
new
URI
(
"http://foo"
));
Response
response
=
Response
.
builder
().
status
(
200
).
headers
(
new
HashMap
<
String
,
Collection
<
String
>>()).
build
();
Response
fourOFourResponse
=
Response
.
builder
().
status
(
404
).
headers
(
new
HashMap
<
String
,
Collection
<
String
>>()).
build
();
doReturn
(
fourOFourResponse
).
doReturn
(
response
).
when
(
client
).
execute
(
any
(
Request
.
class
),
any
(
Request
.
Options
.
class
));
RetryableFeignLoadBalancer
feignLb
=
new
RetryableFeignLoadBalancer
(
lb
,
config
,
inspector
,
loadBalancedRetryPolicyFactory
);
FeignLoadBalancer
.
RibbonResponse
ribbonResponse
=
feignLb
.
execute
(
request
,
null
);
assertEquals
(
200
,
ribbonResponse
.
toResponse
().
status
());
verify
(
client
,
times
(
2
)).
execute
(
any
(
Request
.
class
),
any
(
Request
.
Options
.
class
));
}
@Test
public
void
getRequestSpecificRetryHandler
()
throws
Exception
{
RibbonLoadBalancerContext
lbContext
=
new
RibbonLoadBalancerContext
(
lb
,
config
);
SpringClientFactory
clientFactory
=
mock
(
SpringClientFactory
.
class
);
...
...
spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/RibbonLoadBalancedRetryPolicyFactoryTest.java
View file @
8dcf5440
...
...
@@ -86,6 +86,7 @@ public class RibbonLoadBalancedRetryPolicyFactoryTest {
doReturn
(
nextServer
).
when
(
config
).
getPropertyAsInteger
(
eq
(
CommonClientConfigKey
.
MaxAutoRetriesNextServer
),
anyInt
());
doReturn
(
retryOnAllOps
).
when
(
config
).
get
(
eq
(
CommonClientConfigKey
.
OkToRetryOnAllOperations
),
anyBoolean
());
doReturn
(
retryOnAllOps
).
when
(
config
).
getPropertyAsBoolean
(
eq
(
CommonClientConfigKey
.
OkToRetryOnAllOperations
),
anyBoolean
());
doReturn
(
""
).
when
(
config
).
getPropertyAsString
(
eq
(
RibbonLoadBalancedRetryPolicy
.
RETRYABLE_STATUS_CODES
),
eq
(
""
));
doReturn
(
server
.
getServiceId
()).
when
(
config
).
getClientName
();
doReturn
(
config
).
when
(
clientFactory
).
getClientConfig
(
eq
(
server
.
getServiceId
()));
clientFactory
.
getLoadBalancerContext
(
server
.
getServiceId
()).
setRetryHandler
(
new
DefaultLoadBalancerRetryHandler
(
config
));
...
...
@@ -97,6 +98,7 @@ public class RibbonLoadBalancedRetryPolicyFactoryTest {
LoadBalancedRetryContext
context
=
new
LoadBalancedRetryContext
(
null
,
request
);
assertThat
(
policy
.
canRetryNextServer
(
context
),
is
(
true
));
assertThat
(
policy
.
canRetrySameServer
(
context
),
is
(
false
));
assertThat
(
policy
.
retryableStatusCode
(
400
),
is
(
false
));
}
@Test
...
...
@@ -112,6 +114,7 @@ public class RibbonLoadBalancedRetryPolicyFactoryTest {
doReturn
(
nextServer
).
when
(
config
).
getPropertyAsInteger
(
eq
(
CommonClientConfigKey
.
MaxAutoRetriesNextServer
),
anyInt
());
doReturn
(
retryOnAllOps
).
when
(
config
).
get
(
eq
(
CommonClientConfigKey
.
OkToRetryOnAllOperations
),
anyBoolean
());
doReturn
(
retryOnAllOps
).
when
(
config
).
getPropertyAsBoolean
(
eq
(
CommonClientConfigKey
.
OkToRetryOnAllOperations
),
anyBoolean
());
doReturn
(
""
).
when
(
config
).
getPropertyAsString
(
eq
(
RibbonLoadBalancedRetryPolicy
.
RETRYABLE_STATUS_CODES
),
eq
(
""
));
doReturn
(
server
.
getServiceId
()).
when
(
config
).
getClientName
();
doReturn
(
config
).
when
(
clientFactory
).
getClientConfig
(
eq
(
server
.
getServiceId
()));
clientFactory
.
getLoadBalancerContext
(
server
.
getServiceId
()).
setRetryHandler
(
new
DefaultLoadBalancerRetryHandler
(
config
));
...
...
@@ -123,6 +126,7 @@ public class RibbonLoadBalancedRetryPolicyFactoryTest {
LoadBalancedRetryContext
context
=
new
LoadBalancedRetryContext
(
null
,
request
);
assertThat
(
policy
.
canRetryNextServer
(
context
),
is
(
false
));
assertThat
(
policy
.
canRetrySameServer
(
context
),
is
(
false
));
assertThat
(
policy
.
retryableStatusCode
(
400
),
is
(
false
));
}
@Test
...
...
@@ -138,6 +142,7 @@ public class RibbonLoadBalancedRetryPolicyFactoryTest {
doReturn
(
nextServer
).
when
(
config
).
getPropertyAsInteger
(
eq
(
CommonClientConfigKey
.
MaxAutoRetriesNextServer
),
anyInt
());
doReturn
(
retryOnAllOps
).
when
(
config
).
get
(
eq
(
CommonClientConfigKey
.
OkToRetryOnAllOperations
),
anyBoolean
());
doReturn
(
retryOnAllOps
).
when
(
config
).
getPropertyAsBoolean
(
eq
(
CommonClientConfigKey
.
OkToRetryOnAllOperations
),
anyBoolean
());
doReturn
(
""
).
when
(
config
).
getPropertyAsString
(
eq
(
RibbonLoadBalancedRetryPolicy
.
RETRYABLE_STATUS_CODES
),
eq
(
""
));
doReturn
(
server
.
getServiceId
()).
when
(
config
).
getClientName
();
doReturn
(
config
).
when
(
clientFactory
).
getClientConfig
(
eq
(
server
.
getServiceId
()));
clientFactory
.
getLoadBalancerContext
(
server
.
getServiceId
()).
initWithNiwsConfig
(
config
);
...
...
@@ -149,6 +154,7 @@ public class RibbonLoadBalancedRetryPolicyFactoryTest {
LoadBalancedRetryContext
context
=
new
LoadBalancedRetryContext
(
null
,
request
);
assertThat
(
policy
.
canRetryNextServer
(
context
),
is
(
true
));
assertThat
(
policy
.
canRetrySameServer
(
context
),
is
(
true
));
assertThat
(
policy
.
retryableStatusCode
(
400
),
is
(
false
));
}
@Test
...
...
@@ -161,6 +167,7 @@ public class RibbonLoadBalancedRetryPolicyFactoryTest {
doReturn
(
nextServer
).
when
(
config
).
get
(
eq
(
CommonClientConfigKey
.
MaxAutoRetriesNextServer
),
anyInt
());
doReturn
(
false
).
when
(
config
).
get
(
eq
(
CommonClientConfigKey
.
OkToRetryOnAllOperations
),
eq
(
false
));
doReturn
(
config
).
when
(
clientFactory
).
getClientConfig
(
eq
(
server
.
getServiceId
()));
doReturn
(
""
).
when
(
config
).
getPropertyAsString
(
eq
(
RibbonLoadBalancedRetryPolicy
.
RETRYABLE_STATUS_CODES
),
eq
(
""
));
clientFactory
.
getLoadBalancerContext
(
server
.
getServiceId
()).
setRetryHandler
(
new
DefaultLoadBalancerRetryHandler
(
config
));
RibbonLoadBalancerClient
client
=
getRibbonLoadBalancerClient
(
server
);
RibbonLoadBalancedRetryPolicyFactory
factory
=
new
RibbonLoadBalancedRetryPolicyFactory
(
clientFactory
);
...
...
@@ -189,9 +196,32 @@ public class RibbonLoadBalancedRetryPolicyFactoryTest {
}
}
assertThat
(
context
.
isExhaustedOnly
(),
is
(
true
));
assertThat
(
policy
.
retryableStatusCode
(
400
),
is
(
false
));
verify
(
context
,
times
(
4
)).
setServiceInstance
(
any
(
ServiceInstance
.
class
));
}
@Test
public
void
testRetryableStatusCodest
()
throws
Exception
{
int
sameServer
=
3
;
int
nextServer
=
3
;
RibbonServer
server
=
getRibbonServer
();
IClientConfig
config
=
mock
(
IClientConfig
.
class
);
doReturn
(
sameServer
).
when
(
config
).
get
(
eq
(
CommonClientConfigKey
.
MaxAutoRetries
),
anyInt
());
doReturn
(
nextServer
).
when
(
config
).
get
(
eq
(
CommonClientConfigKey
.
MaxAutoRetriesNextServer
),
anyInt
());
doReturn
(
false
).
when
(
config
).
get
(
eq
(
CommonClientConfigKey
.
OkToRetryOnAllOperations
),
eq
(
false
));
doReturn
(
config
).
when
(
clientFactory
).
getClientConfig
(
eq
(
server
.
getServiceId
()));
doReturn
(
"404,502,foo, ,"
).
when
(
config
).
getPropertyAsString
(
eq
(
RibbonLoadBalancedRetryPolicy
.
RETRYABLE_STATUS_CODES
),
eq
(
""
));
clientFactory
.
getLoadBalancerContext
(
server
.
getServiceId
()).
setRetryHandler
(
new
DefaultLoadBalancerRetryHandler
(
config
));
RibbonLoadBalancerClient
client
=
getRibbonLoadBalancerClient
(
server
);
RibbonLoadBalancedRetryPolicyFactory
factory
=
new
RibbonLoadBalancedRetryPolicyFactory
(
clientFactory
);
LoadBalancedRetryPolicy
policy
=
factory
.
create
(
server
.
getServiceId
(),
client
);
HttpRequest
request
=
mock
(
HttpRequest
.
class
);
doReturn
(
HttpMethod
.
GET
).
when
(
request
).
getMethod
();
assertThat
(
policy
.
retryableStatusCode
(
400
),
is
(
false
));
assertThat
(
policy
.
retryableStatusCode
(
404
),
is
(
true
));
assertThat
(
policy
.
retryableStatusCode
(
502
),
is
(
true
));
}
protected
RibbonLoadBalancerClient
getRibbonLoadBalancerClient
(
RibbonServer
ribbonServer
)
{
given
(
this
.
loadBalancer
.
getName
()).
willReturn
(
ribbonServer
.
getServiceId
());
...
...
spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/apache/RibbonLoadBalancingHttpClientTests.java
View file @
8dcf5440
...
...
@@ -19,6 +19,7 @@ package org.springframework.cloud.netflix.ribbon.apache;
import
java.io.IOException
;
import
java.net.URI
;
import
org.apache.http.HttpResponse
;
import
org.apache.http.StatusLine
;
import
org.apache.http.client.HttpClient
;
import
org.apache.http.client.config.RequestConfig
;
import
org.apache.http.client.methods.HttpUriRequest
;
...
...
@@ -29,6 +30,7 @@ import org.junit.Test;
import
org.mockito.ArgumentCaptor
;
import
org.springframework.cloud.client.loadbalancer.LoadBalancedRetryPolicyFactory
;
import
org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration
;
import
org.springframework.cloud.netflix.ribbon.RibbonLoadBalancedRetryPolicy
;
import
org.springframework.cloud.netflix.ribbon.RibbonLoadBalancedRetryPolicyFactory
;
import
org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerContext
;
import
org.springframework.cloud.netflix.ribbon.ServerIntrospector
;
...
...
@@ -185,7 +187,7 @@ public class RibbonLoadBalancingHttpClientTests {
private
RetryableRibbonLoadBalancingHttpClient
setupClientForRetry
(
int
retriesNextServer
,
int
retriesSameServer
,
boolean
retryable
,
boolean
retryOnAllOps
,
String
serviceName
,
String
host
,
int
port
,
HttpClient
delegate
,
ILoadBalancer
lb
)
throws
Exception
{
HttpClient
delegate
,
ILoadBalancer
lb
,
String
statusCodes
)
throws
Exception
{
ServerIntrospector
introspector
=
mock
(
ServerIntrospector
.
class
);
RetryHandler
retryHandler
=
new
DefaultLoadBalancerRetryHandler
(
retriesSameServer
,
retriesNextServer
,
retryable
);
doReturn
(
new
Server
(
host
,
port
)).
when
(
lb
).
chooseServer
(
eq
(
serviceName
));
...
...
@@ -193,10 +195,12 @@ public class RibbonLoadBalancingHttpClientTests {
clientConfig
.
set
(
CommonClientConfigKey
.
OkToRetryOnAllOperations
,
retryOnAllOps
);
clientConfig
.
set
(
CommonClientConfigKey
.
MaxAutoRetriesNextServer
,
retriesNextServer
);
clientConfig
.
set
(
CommonClientConfigKey
.
MaxAutoRetries
,
retriesSameServer
);
clientConfig
.
set
(
RibbonLoadBalancedRetryPolicy
.
RETRYABLE_STATUS_CODES
,
statusCodes
);
clientConfig
.
setClientName
(
serviceName
);
RibbonLoadBalancerContext
context
=
new
RibbonLoadBalancerContext
(
lb
,
clientConfig
,
retryHandler
);
SpringClientFactory
clientFactory
=
mock
(
SpringClientFactory
.
class
);
doReturn
(
context
).
when
(
clientFactory
).
getLoadBalancerContext
(
eq
(
serviceName
));
doReturn
(
clientConfig
).
when
(
clientFactory
).
getClientConfig
(
eq
(
serviceName
));
LoadBalancedRetryPolicyFactory
factory
=
new
RibbonLoadBalancedRetryPolicyFactory
(
clientFactory
);
RetryableRibbonLoadBalancingHttpClient
client
=
new
RetryableRibbonLoadBalancingHttpClient
(
clientConfig
,
introspector
,
factory
);
client
.
setLoadBalancer
(
lb
);
...
...
@@ -217,10 +221,13 @@ public class RibbonLoadBalancingHttpClientTests {
URI
uri
=
new
URI
(
"http://"
+
host
+
":"
+
port
);
HttpClient
delegate
=
mock
(
HttpClient
.
class
);
final
HttpResponse
response
=
mock
(
HttpResponse
.
class
);
StatusLine
statusLine
=
mock
(
StatusLine
.
class
);
doReturn
(
200
).
when
(
statusLine
).
getStatusCode
();
doReturn
(
statusLine
).
when
(
response
).
getStatusLine
();
doThrow
(
new
IOException
(
"boom"
)).
doReturn
(
response
).
when
(
delegate
).
execute
(
any
(
HttpUriRequest
.
class
));
ILoadBalancer
lb
=
mock
(
ILoadBalancer
.
class
);
RetryableRibbonLoadBalancingHttpClient
client
=
setupClientForRetry
(
retriesNextServer
,
retriesSameServer
,
retryable
,
retryOnAllOps
,
serviceName
,
host
,
port
,
delegate
,
lb
);
serviceName
,
host
,
port
,
delegate
,
lb
,
""
);
RibbonApacheHttpRequest
request
=
mock
(
RibbonApacheHttpRequest
.
class
);
doReturn
(
uri
).
when
(
request
).
getURI
();
doReturn
(
method
).
when
(
request
).
getMethod
();
...
...
@@ -246,11 +253,14 @@ public class RibbonLoadBalancingHttpClientTests {
URI
uri
=
new
URI
(
"http://"
+
host
+
":"
+
port
);
HttpClient
delegate
=
mock
(
HttpClient
.
class
);
final
HttpResponse
response
=
mock
(
HttpResponse
.
class
);
StatusLine
statusLine
=
mock
(
StatusLine
.
class
);
doReturn
(
200
).
when
(
statusLine
).
getStatusCode
();
doReturn
(
statusLine
).
when
(
response
).
getStatusLine
();
doThrow
(
new
IOException
(
"boom"
)).
doThrow
(
new
IOException
(
"boom again"
)).
doReturn
(
response
).
when
(
delegate
).
execute
(
any
(
HttpUriRequest
.
class
));
ILoadBalancer
lb
=
mock
(
ILoadBalancer
.
class
);
RetryableRibbonLoadBalancingHttpClient
client
=
setupClientForRetry
(
retriesNextServer
,
retriesSameServer
,
retryable
,
retryOnAllOps
,
serviceName
,
host
,
port
,
delegate
,
lb
);
serviceName
,
host
,
port
,
delegate
,
lb
,
""
);
RibbonApacheHttpRequest
request
=
mock
(
RibbonApacheHttpRequest
.
class
);
doReturn
(
uri
).
when
(
request
).
getURI
();
doReturn
(
method
).
when
(
request
).
getMethod
();
...
...
@@ -276,11 +286,14 @@ public class RibbonLoadBalancingHttpClientTests {
URI
uri
=
new
URI
(
"http://"
+
host
+
":"
+
port
);
HttpClient
delegate
=
mock
(
HttpClient
.
class
);
final
HttpResponse
response
=
mock
(
HttpResponse
.
class
);
StatusLine
statusLine
=
mock
(
StatusLine
.
class
);
doReturn
(
200
).
when
(
statusLine
).
getStatusCode
();
doReturn
(
statusLine
).
when
(
response
).
getStatusLine
();
doThrow
(
new
IOException
(
"boom"
)).
doThrow
(
new
IOException
(
"boom again"
)).
doReturn
(
response
).
when
(
delegate
).
execute
(
any
(
HttpUriRequest
.
class
));
ILoadBalancer
lb
=
mock
(
ILoadBalancer
.
class
);
RetryableRibbonLoadBalancingHttpClient
client
=
setupClientForRetry
(
retriesNextServer
,
retriesSameServer
,
retryable
,
retryOnAllOps
,
serviceName
,
host
,
port
,
delegate
,
lb
);
serviceName
,
host
,
port
,
delegate
,
lb
,
""
);
RibbonApacheHttpRequest
request
=
mock
(
RibbonApacheHttpRequest
.
class
);
doReturn
(
method
).
when
(
request
).
getMethod
();
doReturn
(
uri
).
when
(
request
).
getURI
();
...
...
@@ -309,7 +322,7 @@ public class RibbonLoadBalancingHttpClientTests {
when
(
delegate
).
execute
(
any
(
HttpUriRequest
.
class
));
ILoadBalancer
lb
=
mock
(
ILoadBalancer
.
class
);
RetryableRibbonLoadBalancingHttpClient
client
=
setupClientForRetry
(
retriesNextServer
,
retriesSameServer
,
retryable
,
retryOnAllOps
,
serviceName
,
host
,
port
,
delegate
,
lb
);
serviceName
,
host
,
port
,
delegate
,
lb
,
""
);
RibbonApacheHttpRequest
request
=
mock
(
RibbonApacheHttpRequest
.
class
);
doReturn
(
method
).
when
(
request
).
getMethod
();
doReturn
(
uri
).
when
(
request
).
getURI
();
...
...
@@ -326,6 +339,42 @@ public class RibbonLoadBalancingHttpClientTests {
}
}
@Test
public
void
testRetryOnStatusCode
()
throws
Exception
{
int
retriesNextServer
=
0
;
int
retriesSameServer
=
1
;
boolean
retryable
=
true
;
boolean
retryOnAllOps
=
false
;
String
serviceName
=
"foo"
;
String
host
=
serviceName
;
int
port
=
80
;
HttpMethod
method
=
HttpMethod
.
GET
;
URI
uri
=
new
URI
(
"http://"
+
host
+
":"
+
port
);
HttpClient
delegate
=
mock
(
HttpClient
.
class
);
final
HttpResponse
response
=
mock
(
HttpResponse
.
class
);
StatusLine
statusLine
=
mock
(
StatusLine
.
class
);
doReturn
(
200
).
when
(
statusLine
).
getStatusCode
();
doReturn
(
statusLine
).
when
(
response
).
getStatusLine
();
final
HttpResponse
fourOFourResponse
=
mock
(
HttpResponse
.
class
);
StatusLine
fourOFourStatusLine
=
mock
(
StatusLine
.
class
);
doReturn
(
404
).
when
(
fourOFourStatusLine
).
getStatusCode
();
doReturn
(
fourOFourStatusLine
).
when
(
fourOFourResponse
).
getStatusLine
();
doReturn
(
fourOFourResponse
).
doReturn
(
response
).
when
(
delegate
).
execute
(
any
(
HttpUriRequest
.
class
));
ILoadBalancer
lb
=
mock
(
ILoadBalancer
.
class
);
RetryableRibbonLoadBalancingHttpClient
client
=
setupClientForRetry
(
retriesNextServer
,
retriesSameServer
,
retryable
,
retryOnAllOps
,
serviceName
,
host
,
port
,
delegate
,
lb
,
"404"
);
RibbonApacheHttpRequest
request
=
mock
(
RibbonApacheHttpRequest
.
class
);
doReturn
(
uri
).
when
(
request
).
getURI
();
doReturn
(
method
).
when
(
request
).
getMethod
();
doReturn
(
request
).
when
(
request
).
withNewUri
(
any
(
URI
.
class
));
HttpUriRequest
uriRequest
=
mock
(
HttpUriRequest
.
class
);
doReturn
(
uri
).
when
(
uriRequest
).
getURI
();
doReturn
(
uriRequest
).
when
(
request
).
toRequest
(
any
(
RequestConfig
.
class
));
RibbonApacheHttpResponse
returnedResponse
=
client
.
execute
(
request
,
null
);
verify
(
delegate
,
times
(
2
)).
execute
(
any
(
HttpUriRequest
.
class
));
verify
(
lb
,
times
(
0
)).
chooseServer
(
eq
(
serviceName
));
}
@Configuration
protected
static
class
UseDefaults
{
...
...
@@ -395,8 +444,12 @@ public class RibbonLoadBalancingHttpClientTests {
ReflectionTestUtils
.
setField
(
client
,
"delegate"
,
delegate
);
ReflectionTestUtils
.
setField
(
client
,
"lb"
,
loadBalancer
);
HttpResponse
httpResponse
=
mock
(
HttpResponse
.
class
);
StatusLine
statusLine
=
mock
(
StatusLine
.
class
);
doReturn
(
200
).
when
(
statusLine
).
getStatusCode
();
doReturn
(
statusLine
).
when
(
httpResponse
).
getStatusLine
();
given
(
delegate
.
execute
(
any
(
HttpUriRequest
.
class
))).
willReturn
(
mock
(
HttpResponse
.
class
)
);
httpResponse
);
RibbonApacheHttpRequest
request
=
mock
(
RibbonApacheHttpRequest
.
class
);
doReturn
(
uri
).
when
(
request
).
getURI
();
doReturn
(
request
).
when
(
request
).
withNewUri
(
any
(
URI
.
class
));
...
...
spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/support/RetryableStatusCodeExceptionTest.java
0 → 100644
View file @
8dcf5440
/*
*
* * Copyright 2013-2016 the original author or authors.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * http://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
package
org
.
springframework
.
cloud
.
netflix
.
ribbon
.
support
;
import
org.junit.Test
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
/**
* @author Ryan Baxter
*/
public
class
RetryableStatusCodeExceptionTest
{
@Test
public
void
testMessage
()
{
RetryableStatusCodeException
ex
=
new
RetryableStatusCodeException
(
"foo"
,
404
);
assertEquals
(
"Service foo returned a status code of 404"
,
ex
.
getMessage
());
}
}
\ No newline at end of file
spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/apache/HttpClientRibbonRetryIntegrationTests.java
View file @
8dcf5440
...
...
@@ -47,7 +47,8 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
"disableretry.ribbon.MaxAutoRetriesNextServer: 1"
,
"zuul.routes.globalretrydisabled: /globalretrydisabled/**"
,
"globalretrydisabled.ribbon.MaxAutoRetries: 1"
,
"globalretrydisabled.ribbon.MaxAutoRetriesNextServer: 1"
"globalretrydisabled.ribbon.MaxAutoRetriesNextServer: 1"
,
"retryable.ribbon.retryableStatusCodes: 404,403"
})
@DirtiesContext
public
class
HttpClientRibbonRetryIntegrationTests
extends
RibbonRetryIntegrationTestBase
{
...
...
spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/okhttp/OkHttpRibbonRetryIntegrationTests.java
View file @
8dcf5440
...
...
@@ -36,6 +36,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
"zuul.routes.retryable: /retryable/**"
,
"zuul.routes.retryable.retryable: true"
,
"retryable.ribbon.OkToRetryOnAllOperations: true"
,
"retryable.ribbon.retryableStatusCodes: 404"
,
"retryable.ribbon.MaxAutoRetries: 1"
,
"retryable.ribbon.MaxAutoRetriesNextServer: 1"
,
"zuul.routes.getretryable: /getretryable/**"
,
...
...
spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/support/RibbonRetryIntegrationTestBase.java
View file @
8dcf5440
...
...
@@ -25,8 +25,15 @@ import org.junit.Test;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.boot.autoconfigure.EnableAutoConfiguration
;
import
org.springframework.boot.test.web.client.TestRestTemplate
;
import
org.springframework.cloud.client.loadbalancer.LoadBalancedRetryPolicy
;
import
org.springframework.cloud.client.loadbalancer.LoadBalancedRetryPolicyFactory
;
import
org.springframework.cloud.client.loadbalancer.ServiceInstanceChooser
;
import
org.springframework.cloud.netflix.ribbon.RibbonClient
;
import
org.springframework.cloud.netflix.ribbon.RibbonClients
;
import
org.springframework.cloud.netflix.ribbon.RibbonLoadBalancedRetryPolicy
;
import
org.springframework.cloud.netflix.ribbon.RibbonLoadBalancedRetryPolicyFactory
;
import
org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerContext
;
import
org.springframework.cloud.netflix.ribbon.SpringClientFactory
;
import
org.springframework.cloud.netflix.ribbon.StaticServerList
;
import
org.springframework.cloud.netflix.zuul.EnableZuulProxy
;
import
org.springframework.context.annotation.Bean
;
...
...
@@ -37,6 +44,7 @@ import org.springframework.http.HttpStatus;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestMethod
;
import
org.springframework.web.bind.annotation.ResponseStatus
;
import
org.springframework.web.bind.annotation.RestController
;
import
com.netflix.loadbalancer.Server
;
...
...
@@ -75,6 +83,15 @@ public abstract class RibbonRetryIntegrationTestBase {
}
@Test
public
void
retryableFourOFour
()
{
String
uri
=
"/retryable/404everyothererror"
;
ResponseEntity
<
String
>
result
=
new
TestRestTemplate
().
exchange
(
"http://localhost:"
+
this
.
port
+
uri
,
HttpMethod
.
GET
,
new
HttpEntity
<>((
Void
)
null
),
String
.
class
);
assertEquals
(
HttpStatus
.
OK
,
result
.
getStatusCode
());
}
@Test
public
void
postRetryOK
()
{
String
uri
=
"/retryable/posteveryothererror"
;
ResponseEntity
<
String
>
result
=
new
TestRestTemplate
().
exchange
(
...
...
@@ -161,6 +178,17 @@ public abstract class RibbonRetryIntegrationTestBase {
return
timeout
();
}
@RequestMapping
(
"/404everyothererror"
)
@ResponseStatus
(
HttpStatus
.
NOT_FOUND
)
public
ResponseEntity
<
String
>
fourOFourError
()
{
boolean
shouldError
=
error
;
error
=
!
error
;
if
(
shouldError
)
{
return
new
ResponseEntity
<
String
>(
"not found"
,
HttpStatus
.
NOT_FOUND
);
}
return
new
ResponseEntity
<
String
>(
"no error"
,
HttpStatus
.
OK
);
}
}
@Configuration
...
...
@@ -173,6 +201,46 @@ public abstract class RibbonRetryIntegrationTestBase {
public
ServerList
<
Server
>
ribbonServerList
()
{
return
new
StaticServerList
<>(
new
Server
(
"localhost"
,
this
.
port
));
}
}
@Configuration
public
static
class
FourOFourRetryableRibbonConfiguration
extends
RibbonClientConfiguration
{
@Bean
public
LoadBalancedRetryPolicyFactory
loadBalancedRetryPolicyFactory
(
SpringClientFactory
factory
)
{
return
new
MyRibbonRetryPolicyFactory
(
factory
);
}
public
static
class
MyRibbonRetryPolicyFactory
extends
RibbonLoadBalancedRetryPolicyFactory
{
private
SpringClientFactory
factory
;
public
MyRibbonRetryPolicyFactory
(
SpringClientFactory
clientFactory
)
{
super
(
clientFactory
);
this
.
factory
=
clientFactory
;
}
@Override
public
LoadBalancedRetryPolicy
create
(
String
serviceId
,
ServiceInstanceChooser
loadBalanceChooser
)
{
RibbonLoadBalancerContext
lbContext
=
this
.
factory
.
getLoadBalancerContext
(
serviceId
);
return
new
MyLoadBalancedRetryPolicy
(
serviceId
,
lbContext
,
loadBalanceChooser
);
}
class
MyLoadBalancedRetryPolicy
extends
RibbonLoadBalancedRetryPolicy
{
public
MyLoadBalancedRetryPolicy
(
String
serviceId
,
RibbonLoadBalancerContext
context
,
ServiceInstanceChooser
loadBalanceChooser
)
{
super
(
serviceId
,
context
,
loadBalanceChooser
);
}
@Override
public
boolean
retryableStatusCode
(
int
statusCode
)
{
if
(
statusCode
==
HttpStatus
.
NOT_FOUND
.
value
())
{
return
true
;
}
return
super
.
retryableStatusCode
(
statusCode
);
}
}
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment