Spring Ribbon RestTemplate - Mix Eureka and Real URLs - spring

I have a need to mix calls to a Spring Rest Template using either a Eureka-compliant service name (example-service-name) or a real url (http://my-url.com).
The Eureka-friendly URLs work fine, as Ribbon can look them up without issue. Obviously real URLs fail because they can't be found.
I'd like to be able to integrate Eureka-URLs over time, while maintaining the existing functionality for Spring property-driven direct URLs.
Can I
Configure Ribbon to fall back to a default non-Eureka behavior in the event it fails to resolve a URL ?
or
Spoof Eureka Name/URL pairs in my local Spring configuration and include them in Ribbon's Eureka url resolution ?
Edit:
Real URLs are failing because the Ribbon client throws an exception if a Eureka lookup fails
Caused by: java.lang.IllegalStateException: No instances available for http://my-url.com
at org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient.execute(RibbonLoadBalancerClient.java:75)

you can regist url as a fake service use this:
my-url:
ribbon:
listOfServers: my-url.com
NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList
and then use http://my-url/xx/xx

Related

Configure FeignClient to use url by env variable without disabling Eureka

My current environment is a Spring Cloud setup using Eureka and I have multiple Feign clients in the application. What I want to do is to allow most of my Feign clients to resolve their services via the discovery server but prevent one or two from doing so in order to use my local instance that I am currently developing on. I'm running the service I'm developing and the client application locally.
I would like the client application to use discovery for all over service discovery and override one Feign Client to use only my local running service.
Is there a way to do this without disabling Eureka on the client? I have explored these two questions (one, two) and have not managed to get the listOfServers field to have any impact unless I disabled Eureka. If it matters in working on this I made the service I wish to connect to not register with eureka.
You can specify a URL for a specific FeignClient without disabling Eureka client with property <ribbonclientname>.ribbon.NIWSServerListClassName property.
Assume that service id for directing routing is testA. You can define the below property without disabling Eureka client.
testA:
ribbon:
NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList
listOfServers: ${url for your test server}
If you specify com.netflix.loadbalancerConfigurationBasedServerList as NIWSServerListClassName, ribbon client inside your Feign client will use address that was given via listOfServers property without disabling eureka.
I got a way to pass the environment variables in a very simple way:
interface FeignClient
#FeignClient(url = "https://"+"\${url}", name = "limit", decode404 = true)
interface HbFeignClient {
#GetMapping("/credit-limit")
fun getLimitCompany(#RequestParam(required = true) companyId: Long): ResponseEntity<Any>
properties
#URL
url=${URL}
.env
URL=https:localhost:8080

routing differences through zuul proxy with eureka

I have two machines (with same application) register to eureka server.
all requests to these services are through zuul proxy.
my application.properties of my backend services is:
spring.application.name=core
my application.properties of my zuul proxy is:
zuul.sensitiveHeaders=Set-Cookie
zuul.routes.address.path=/to-address/**
zuul.routes.address.url=http://localhost:8888
zuul.routes.service.path=/by-service/**
zuul.routes.service.url=CORE
I have two questions:
All three request below are working, which one should I use?
What is the difference with upper case and lower case?
http://localhost:9090/api/by-service/customer/1
http://localhost:9090/api/core/customer/1
http://localhost:9090/api/CORE/customer/1
When I call the service in the following way:
http://localhost:9090/api/to-address/customer/1
I noticed that a new session is being created by my core server, which force my user to login again. Any idea why?
As you can see it's the same method (same filter, same application...) with just a routing difference.
you need to use req.getRequestedSessionId() instead of req.getSession().getId().

Zuul proxy that discovers routes dynamically

I have a simple Zuul app that has a single route in the application.yml to route to my microservice. It's working.
However, what I'm looking for is a more dynamic solution where I can wire up routes dynamically, either through code or perhaps by POSTing to some Zuul endpoints during a build (possibly by using springfox and a swagger definition from microservices). I could not find an API for Zuul.
I'm somewhat aware of Eureka and that seems like a solution to abstract away the routing by doing discovery. However, I'm curious if there's a solution without introducing Eureka. If there's a way to wire up these routes in Zuul during a build vs. having to edit the application.yml every time.
Thanks in advance.
If you go for Eureka this will actually work ootb. Zuul as packaged in spring cloud will automatically expose every service using its name. So if you register a service called users in Eureka, Zuul will automatically create a route /users forwarding to the instances by default. That will only allow simple url structures but should solve your problem.
Please see the official documentation for details:
By convention, a service with the ID "users", will receive requests from the proxy located at /users (with the prefix stripped). The proxy uses Ribbon to locate an instance to forward to via discovery, and all requests are executed in a hystrix command, …
I'm actually editing a blog post about this exact topic (Routing and Filtering using Spring Cloud Zuul Server) but the source code has been available and working for some time now. Feel free to use it as a reference:
https://bitbucket.org/asimio/zuulserver
https://bitbucket.org/asimio/discoveryserver (in case routes are configured with serviceIds)
https://bitbucket.org/asimio/demo-config-properties/src (Zuul-Server-refreshable.yml where routes are dynamically updated).
Look at the refreshable Spring profile settings. This Zuul setup works with both, hard-coding routes url or discovered using Eureka.
It also acting as a Spring Cloud Config client so that routes could be dynamically updated via Git, which is also covered in another blog post: Refreshable Configuration using Spring Cloud Config Server, Spring Cloud Bus, RabbitMQ and Git.

Route Existing Services via ZUUL without adding routing rule

I am trying to route existing services via Spring cloud Netflix Zuul.
I have an existing service available at below url,
http://localhost:3080/query-service/getquery/1
Out of the box, with zuul I can route to the service as below,
localhost:9000/queryservice-id/queryservice/getquery/1, with "queryservice-id" as the service-id of the service when it is registered in Service Registry. The zuul port is 9000.
I do not want to change the context path and service path information when accessing the service via ZUUL.
With ZUUL, I want to access the service as below,
http://localhost:9000/query-service/getquery/1
I do want to prefix with the "serviceId". This is because I do not want to impact any existing clients of the service. Only the host and port changes, without serviceId.
I was able to accomplish it as below with ZUUL Configuration,
zuul:
routes:
query-service:
path: /query-service/**
serviceId: query-service
stripPrefix: false
With the above configuration, I am able to only use the zuul host and port, the other service specific information remains as before. Seems like stripPrefix is helping in routing without the serviceId.
But, I have a lot of services and will be adding more services too.
For every such service, I do not want to be adding a rule like that to ZUUL configuration which will mean rebuilding and recycling the ZUUL Service.
I feel there should be a simpler and better way to accomplish this, without a big effort, because the change I want to do is common to all services
Is there a way to making this change common for alll the services I want
to be routed via ZUUL.
Thanks,
As checked with the Spring Cloud Netflix team this is recommended approach.
https://github.com/spring-cloud/spring-cloud-netflix/issues/1549

Spring cloud config client without Eureka, Ribbon and spring boot

I have spring web application (not spring boot) running in AWS. I am trying to create centralized configuration server. How to refresh the spring-cloud-client after the changing the properties? As per tutorial
Actuator endpoint by sending an empty HTTP POST to the client’s refresh endpoint, http://localhost:8080/refresh, and then confirm it worked by reviewing the http://localhost:8080/message endpoint.
But my aws Ec2 instances are behind the loadbalancer so i can't invoke the client url. I didn't understand the netflix Eureka and Ribbon much but it seems like adding another level of load balancer in the client side. I don't like this approach. Just to change a property i don't want to make the existing project unnecessarily complex. Is there any other way? or Am I misunderstood Eureka/Ribbon usage?
I have looked at the spring-cloud-config-client-without-spring-boot, spring-cloud-config-client-without-auto-configuration none of them have answer. First thread was answered in 2015. Wondering is there any update?
To get the configuration properties from a config server. You can do a http request. Example:
From the documentation we can see:
/{application}/{profile}[/{label}]
/{application}-{profile}.yml <- example
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties
So if you would do a request to http://localhost:8080/applicationName-activeProfile.yml you would receive the properties in .yml format for the application with that name and active profile. Spring boot config clients would automatically provide these values but you will have to provide em manually.
You don't need Eureka/Ribbon for this to work, it's a separate component.
More info: http://cloud.spring.io/spring-cloud-static/spring-cloud.html#_spring_cloud_config
Maybe you could even use spring-cloud-config but I'm not sure what extra configuration is needed without spring-boot.
https://cloud.spring.io/spring-cloud-config/

Resources