Rarely getting ClientException and ZuulException in spring boot, eureka, zuul, ribbon framework - spring-boot

I have configured my project architecture using Spring Boot, Eureka, Zuul, Ribbon frameworks.
Its working fine but sometimes (rarely) getting the following exceptions:
Caused by: com.netflix.client.ClientException: Load balancer does not have available server for client: service1
Caused by: com.netflix.hystrix.exception.HystrixRuntimeException: service1 timed-out and no fallback available.
Below are my services configurations:
Have a look and please let me know if I missed anything which causing the issues for above exceptions.
eureka service application.properties:
server.port=8070
spring.application.name=eureka_service
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.instance.hostname=localhost
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:8070/eureka/
logging.level.com.netflix.eureka=OFF
logging.level.com.netflix.discovery=OFF
zuul service application.properties:
server.port=8071
spring.application.name=zuul_service
zuul.prefix=/api
zuul.routes.service1.path=/service1/**
zuul.routes.service1.service-id=service1
eureka.client.register-with-eureka=true
eureka.client.fetch-registry=true
eureka.instance.hostname=localhost
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:8070/eureka/
ribbon.eureka.enabled=true
service1 application.properties:
server.port=8072
spring.application.name=service1
eureka.client.register-with-eureka=true
eureka.client.fetch-registry=true
eureka.instance.hostname=localhost
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:8070/eureka/
ribbon.eureka.enabled=true
Please let me know if I need to add any other configuration to resolve ?
Thanks.

You can try to increase the Ribbon timeout by setting for example:
ribbon.ReadTimeout=10000
If above code doesn't work you can try by disabling the timeout:
hystrix.command.default.execution.timeout.enabled=false

Related

Spring Cloud API Gateway routing not working

I have designed a micro service prototype using below technologies
Eureka Server
a service
Spring Cloud API Gateway
Above mentioned service are registered in the Eureka Server
API Gateway routing Configuration
server.port=8080
eureka.client.serviceUrl.defaultZone = http://localhost:8083/eureka
spring.application.name=ApiGateway
spring.cloud.gateway.discovery.locator.enabled=true
spring.cloud.gateway.discovery.locator.lower-case-service-id=true
spring.cloud.gateway.routes[0].id=service1
spring.cloud.gateway.routes[0].uri=lb://MICROSERVICE1
spring.cloud.gateway.routes[0].predicates[0]=Path=/service1/**
The service Configuration
server.port=8081
server.address=127.0.0.1
eureka.client.serviceUrl.defaultZone = http://localhost:8083/eureka
spring.application.name=MicroService1
error.whitelabel.enabled= false
Controller
#RestController
#RequestMapping("/service1")
public class HomeController {
#GetMapping("/message")
public String hello() {
return "response from micro service1";
}
}
When I send a request to the gateway it's showing the below error
2020-12-16 22:26:09.770 ERROR 16700 --- [ctor-http-nio-3] a.w.r.e.AbstractErrorWebExceptionHandler : [d3334561-1] 500 Server Error for HTTP GET "/service1/message"
java.net.UnknownHostException: failed to resolve 'LAPTOP-KU56B6A8' after 3 queries
at io.netty.resolver.dns.DnsResolveContext.finishResolve(DnsResolveContext.java:1013) ~[netty-resolver-dns-4.1.55.Final.jar:4.1.55.Final]
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
|_ checkpoint ⇢ org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter [DefaultWebFilterChain]
|_ checkpoint ⇢ HTTP GET "/service1/message" [ExceptionHandlingWebHandler]
How can we solve the above issue?
Add eureka.instance.hostname=localhost in both the microservices instances this will work and not give an error
i have modified the API Gate Way routing Configuration like below
spring.cloud.gateway.routes[0].id=service1
spring.cloud.gateway.routes[0].uri=http://localhost:8081/service1/
spring.cloud.gateway.routes[0].predicates[0]=Path=/service1/**
Now is working fine
Add this bean in your API gateway and you are good to go.
#Bean
public HttpClient httpClient() {
return HttpClient.create().resolver(DefaultAddressResolverGroup.INSTANCE);
}
Add below to both gateway and individual microservice fix the issue
eureka.instance.hostname=localhost
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:8010/eureka/
Add in your application.properties:
spring.cloud.discovery.enabled=true
I have modified my .yaml file with this configuration.
Issue resolved for me.
**server:
port: 9999
spring:
application:
name: gateway-ws
cloud:
gateway:
discovery:
locator:
enabled: true
routes:
- id: userService
uri: http://user-service/
predicates:
- Path=/user/**
- id: contactService
uri: http://contact-service/
predicates:
- Path=/contact/**
eureka:
client:
service-url:
defaultZone: http://localhost:8085/eureka**
This is the only solution works among all of the answers above.
#Bean
public HttpClient httpClient() {
return HttpClient.create().resolver(DefaultAddressResolverGroup.INSTANCE);
}
This is the default behavior, so no effect.
spring.cloud.discovery.enabled=true
This has nothing to do with the discovery client.
It is related with the discovery server.
eureka.instance.hostname=localhost
So if you don't know, just don't mess it up with wrong directions.
hello jebji if you still have this problem
add
spring.cloud.discovery.enabled=true
in application.properties
Only Add the following property into your API gateway:
spring.cloud.discovery.enabled=true
Make sure you already added DevTool maven dependency into your API gateway project but if not then restart it.
add flowing property in application.property file of all eruka client microservice and api gateway , i face same issue and resolve doing same activity
spring.cloud.discovery.enabled=true
spring.cloud.gateway.discovery.locator.lower-case-service-id= true
spring.cloud.gateway.discovery.locator.enabled= true
eureka.instance.hostname=localhost
after adding all the above properties then also if you are facing issue then try the below one,
don't use lb://albums_service , but use lb://albums-service .Because URI don‘t support underline.
You can add the following in application.yml file
spring:
cloud:
gateway:
routes:
- id: test-service
uri: lb://MICROSERVICE1
predicates:
- Path=/microservice1/**
filters:
- RewritePath=/microservice1/(?<segment>.*), /$\{segment}
with this it should works.
Like let say if your microservice1 is url is
localhost:8081/service1/message
then you can define the base path of your microservice1 in api-gateway by setting up the path as i did in above configuration.
The error message is "failed to resolve 'LAPTOP-KU56B6A8'".
This is an DNS issue.
You can set eureka.instance.prefer-ip-address=true in the service.
So it will register with its ip at Eureka and the DNS issue can be avoided.
This is actually the same issue as this QUESTION.
With this ANSWER

Zuul proxy with eureka returning 504 Timeout

I have this scenario where I have an Eureka server, a Zuul proxy and the eureka's clients (some API).
The thing is that when I call the Zuul server it does discover the "service" on Eureka but it returns a 504 status time out.
{
"timestamp":"2020-07-21T18:38:46.408+00:00",
"status":504,
"error":"Gateway Timeout",
"message":""
}
In my application.properties I have:
spring.application.name=zuul-server
eureka.instance.preferIpAddress=true
eureka.client.registerWithEureka=true
eureka.client.fetchRegistry=true
eureka.client.healthcheck.enabled=true
zuul.ignored-services=*
zuul.host.time-to-live=-1
zuul.host.connect-timeout-millis=15000
zuul.host.max-per-route-connections=10000
zuul.host.max-total-connections=5000
zuul.host.socket-timeout-millis=60000
zuul.semaphore.max-semaphores=500
I can't figure it out what's wrong to cause this timeout.
Any helping tips?
For those who eventually face this same problem here is how I solved it.
This is how my final application.properties on the Zuul project is set and working:
spring.application.name=zuul-server
eureka.instance.preferIpAddress=true
eureka.client.registerWithEureka=true
eureka.client.fetchRegistry=true
eureka.client.healthcheck.enabled=true
#zuul.ignored-services=*
#zuul.host.time-to-live=-1
zuul.host.connect-timeout-millis=60000
zuul.host.max-per-route-connections=10000
zuul.host.max-total-connections=5000
zuul.host.socket-timeout-millis=60000
zuul.semaphore.max-semaphores=500
zuul.ribbon.eager-load.enabled= true
hystrix.command.default.execution.isolation.strategy=THREAD
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=40000
ribbon.ConnectTimeout=10000
ribbon.ReadTimeout: 10000
If your IDE complains about "unknown property" just ignore it.

Eureka instances are showing in available

Hi i have 3 instances of Eureka Server. I made the peer connection between these 3 instances by registering them to each other as a client.
Initially my all instances are up and are showing in available-replicas.
But when i down the other two instances yet they are showing in available-replicas.
Please help me with the configuration.
Properties
peer1-
server.port=7555
eureka.instance.hostname=instance01
spring.application.name=EurekaServerCluster
eureka.client.serviceUrl.defaultZone:http://instance02:7555/eureka/,http://instance03:7555/eureka/
eureka.client.register-with-eureka=true
eureka.client.fetch-registry=true
eureka.client.healthcheck.enabled=true
eureka.instance.preferIpAddress=false
peer2-
server.port=7555
eureka.instance.hostname=instance02
spring.application.name=EurekaServerCluster
eureka.client.serviceUrl.defaultZone:http://instance01:7555/eureka/,http://instance03:7555/eureka/
eureka.client.register-with-eureka=true
eureka.client.fetch-registry=true
eureka.client.healthcheck.enabled=true
eureka.instance.preferIpAddress=false
peer3-
server.port=7555
eureka.instance.hostname=instance03
spring.application.name=EurekaServerCluster
eureka.client.serviceUrl.defaultZone:http://instance01:7555/eureka/,http://instance02:7555/eureka/
eureka.client.register-with-eureka=true
eureka.client.fetch-registry=true
eureka.client.healthcheck.enabled=true
eureka.instance.preferIpAddress=false
It happens due to self preservation mode. Read here
You can turn off the mode by putting below property.
eureka.server.enableSelfPreservation: false

Feign Client Prioritizing URL's in yaml over Eureka

I have a Spring Boot application which serves as a Eureka client. The application has the need to call another micro-service through REST, and I wish to make this call using Feign. The issue I am having is, my application is trying to lookup the service name in Eureka, when it is only defined in my applications yaml file.
I apologize for the hard to follow explanation, hopefully the following code snippets will help clarify.
Feign client:
#FeignClient("foo")
#Component
public interface FooServiceProxy{
#RequestMapping(value = "/balance", method = RequestMethod.POST, produces = "application/json")
ServiceResponse execute(ServiceRequest serviceRequest);
}
In my controller who calls this Feign client, the FooServiceProxy is defined using #AutoWired:
#Autowired
private FooServiceProxy fooServiceProxy;
My yaml file is as follows:
spring:
application:
name: app-name
server:
port: 8080
foo:
ribbon:
listOfServers: http://hostname:8081/balance
eureka:
client:
fetchRegistry: false
serviceUrl:
defaultZone: http://eurekasrver:8761/eureka/
My issue is, during run-time, the following error is thrown:
java.lang.RuntimeException: com.netflix.client.ClientException: Load balancer does not have available server for client: foo
Interestingly, if I remove the #EnableEurekaClient annotation from the application, everything works. I believe I understand the problem which is that instead of looking up the server for foo in my yaml file, because the application is a Eureka client, Feign is going straight to Eureka to lookup a server ip, then failing as none can be found. Despite seeming to understand the problem, I have been unable to find a solution online or to think of one myself.
Any help will be appreciated.
Thank you!
Concerning this question, you should take in account that when eureka is on your classpath, all ribbon configuration are charged by eureka, so it'll use eureka server's list.
Spring Cloud uses #RibbonClient to configure the types used by ribbon, like server list. If you have eureka on the classpath, by default it uses the eureka server list (hence your need for the flag to disable eureka).
Commented by spencergibb https://github.com/spring-cloud/spring-cloud-netflix/issues/564
You can try either by adding the NIWSServerListClassName configuration:
`someservice.ribbon:
NIWSServerListClassName:com.netflix.loadbalancer.ConfigurationBasedServerList
listOfServers: server1:80`
Or try the solution proposed in this issue https://github.com/spring-cloud/spring-cloud-netflix/issues/564

How to mock Eureka when doing Integration Tests in Spring?

I am running a simple Junit Testing a Controller in Spring Boot. The test code looks like this:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = {FrontControllerApplication.class})
#WebAppConfiguration
#ComponentScan
#IntegrationTest({"server.port:0", "eureka.client.registerWithEureka:false", "eureka.client.fetchRegistry:false"})
#ActiveProfiles("integrationTest")
public class MyControllerIT {
In the application-integrationTest.properties I have the following Eureka Settings:
####### Eureka
eureka.serviceUrl.default=http://localhost:8767/eureka/
eureka.printDeltaFullDiff=false
eureka.client.refresh.interval=1
eureka.appinfo.replicate.interval=1
eureka.serviceUrlPollIntervalMs=1000
eureka.name=${spring.application.name}
####### Netflix Eureka #######
eureka.client.serviceUrl.defaultZone=http://localhost:8767/eureka/
eureka.client.instanceInfoReplicationIntervalSeconds=1
eureka.client.initialInstanceInfoReplicationIntervalSeconds=0
eureka.instance.virtualHostName=${spring.application.name}
eureka.instance.preferIpAddress=true
eureka.instance.initialStatus=DOWN
eureka.instance.leaseRenewalIntervalInSeconds=3
eureka.instance.leaseExpirationDurationInSeconds=10
eureka.instance.metadataMap.instanceId=${spring.application.name}:${spring.application.instance_id:${random.value}}
eureka.eurekaserver.connectionIdleTimeoutInSeconds=5
eureka.responseCacheAutoExpirationInSeconds=5
when a junit test started I see the following:
2015-09-16 16:46:03,905 ERROR localhost-startStop-1 com.netflix.discovery.DiscoveryClient Can't get a response from http://localhost:8767/eureka/apps/
Can't contact any eureka nodes - possibly a security group issue?
com.sun.jersey.api.client.ClientHandlerException: java.net.ConnectException: Connection refused: connect
at com.sun.jersey.client.apache4.ApacheHttpClient4Handler.handle(ApacheHttpClient4Handler.java:184) ~[jersey-apache-client4-1.11.jar:1.11]
The test passes, that is not the problem, but I see a lot of exception stack traces that has to do with Eureka. The questions is if there is a way to mock eureka or another way to skip brining it up when doing tests?
The benefit would be easier to see relevant stack traces if test would fail and tst would run much faster
Another solution is to disable the Eureka Client in your application.properties or application.yml file under test/resources
applications.properties:
eureka.client.enabled=false
application.yml:
eureka:
client:
enabled: false
This has the benefit of not needing to remeber to include the system property for every JUnit test that requires disabling the Eureka Client.
You can set a system property for eureka.client.enabled=false for tests.
If you're running the tests using gradle you can do this:
tasks.withType(Test) {
systemProperty 'eureka.client.enabled', 'false'
}
If you're running tests in an IDE then you'll have to set the system property there as well.

Resources