application.yaml in the dependency overwrite the application.yaml in my application - spring

In what scenarios , will application.yaml in the dependency overwrite the application.yaml in my application?
Right now I suspect that below yaml codesnippet will be overwritten my yaml in my dependency due to profile include clause
profiles:
include:
- health-check
- redis-pool
redis:
pool:
maxTotal: 80
maxIdle: 80
minIdle: 10
maxWaitMillis: 15000
my yaml in my dependency - application-redis-pool.yaml
redis:
pool:
maxTotal: 150
maxIdle: 10
minIdle: 0
maxWaitMillis: 30000
Can anyone confirm? probably give a full scenarios case?

Related

Not able to change Spring Actuator Port

My application Is running on port 8444 but I want my actuator metrics to be exposed to a different port, by default I can access them via https://localhost:8444/actuator/health but I want them on a different port like 8086
https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#production-ready-customizing-management-server-port
I followed this document and added management.server.port=8086 in my application.yml but it's just showing that site can't be reached
I tried other properties such as changing the endpoint base-path and that seems to be working fine.
I am using Spring boot 2.2.4.RELEASE and Wildfly 18,
Here is my application.yml
server:
port: 8443
servlet:
context-path: /appName
info:
app:
name: name
description: description
version: 1.0
management.endpoints.web.exposure.include: ["health", "info", "prometheus"]
management.endpoint.health.show-details: always
spring:
servlet:
multipart:
max-request-size: 100MB
datasource:
jndi-name: java:/datasource
main:
allow-bean-definition-overriding: true
management:
server:
port: 8086
endpoints:
web:
base-path: /manage

Spring Config server not reachable with docker-compose until client is restarted

I have a 'discovery first' setup with Eureka, Config Server, and my client.
The issue is that these 3 services start in order, but the client-server seems to register too early, and can never find config-server. I've tried a third-party library that allows a wait until config-server:8888 is available, but that doesn't always seem to work either. It's similar to a race condition.
The workaround is that if I docker restart the client-server after everything is up, it registers and finds config-server just fine.
First run of docker-compose:
Fetching config from server at : http://localhost:8888
Connect Timeout Exception on Url - http://localhost:8888. Will be trying the next url if available
When I docker restart the client:
Fetching config from server at : http://a80b001d04a7:8888/
Located environment: name=client-server, profiles=[default], label=null, version=053c8e1b14dc0281d5af0349c9b2cf012c1a346f, state=null
Not sure if my JAVA_OPTS properties aren't being set fast enough from my docker-compose.yml, or there is some networking race condition, or what. I've been going back and forth on this for too long.
My configuration is below:
Here's my docker-compose.yml:
version: '3'
services:
eureka:
image: eureka-server:latest
environment:
- "JAVA_OPTS=-DEUREKA_SERVER=http://eureka:8761/eureka"
ports:
- 8761:8761
config:
image: config-server:latest
environment:
- "JAVA_OPTS=-DEUREKA_SERVER=http://eureka:8761/eureka"
depends_on:
- eureka
ports:
- 8888:8888
client:
image: client-server:latest
environment:
JAVA_OPTS: -DEUREKA_SERVER=http://eureka:8761/eureka
depends_on:
- config
ports:
- 9000:9000
Here's the eureka-server application.yml:
server:
port: 8761
spring:
application:
name: eureka-server
eureka:
client:
registerWithEureka: false
fetchRegistry: false
service-url:
defaultZone: ${EUREKA_SERVER:http://localhost:8761/eureka}
Here's the config-server bootstrap.yml:
server:
port: 8888
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_SERVER:http://localhost:8761/eureka}
spring:
application:
name: config-server
Here's the client-server bootstrap.yml:
spring:
application:
name: client-server
cloud:
config:
discovery:
enabled: true
serviceId: config-server
fast-fail: true
retry:
max-attempts: 10000
max-interval: 1000
eureka:
instance:
hostname: client-server
client:
registerWithEureka: true
fetchRegistry: true
serviceUrl:
defaultZone: ${EUREKA_SERVER:http://localhost:8761/eureka}
Edit:
Using the docker-compose wait library (https://github.com/ufoscout/docker-compose-wait), I can have the client-server wait for eureka and config to be available, then wait 90 seconds (Eureka documentation suggests that registration could take up to 90 seconds), and it seems to work consistently.
Is this an acceptable solution? Feels like a bit of a hack.
Being purist the answer to your question is NO, it is not an acceptable solution, because as it is stated here, Docker removed healthcheck from v3 on for some reason:
Docker have made a conscious decision not to support features that wait for containers to be in a "ready" state. They argue that applications depending on other systems should be resilient to failure.
In the same link, it is described why:
The problem of waiting for a database (for example) to be ready is really just a subset of a much larger problem of distributed systems. In production, your database could become unavailable or move hosts at any time. Your application needs to be resilient to these types of failures.
To handle this, your application should attempt to re-establish a connection to the database after a failure. If the application retries the connection, it should eventually be able to connect to the database.
Basically then, there are three options:
Use v2.1 with healhcheck. See an example here
Use v3 and a tool like wait-for-it or
dockerize as #ortomala-lokni already perfectly explained
Make your application resilient to config-server failure and able config-client to retry the connection on startup
The recommended and acceptable solution is 3). You can use Spring Retry as it is mentioned here. Find below the bootstrap.yml configuration:
spring:
application:
name: config-client
profiles:
active: dev
cloud:
config:
discovery:
enabled: true
service-id: config-server
fail-fast: true
retry:
initial-interval: 1500
multiplier: 1.5
max-attempts: 10000
max-interval: 1000
eureka:
instance:
hostname: config-client
client:
registerWithEureka: true
fetchRegistry: true
serviceUrl:
defaultZone: ${EUREKA_SERVER:http://localhost:8761/eureka}
BTW I found an error in your spring configuration. It is fail-fast and not fast-fail.
Remember to include the following dependencies (or similar if you are using gradle):
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
You can find a very well configuration (and explanation) here taking also into account resiliency during the registering process in the Eureka Server.
When having a microservices environment we must think of the resiliency of our environment when platform services like config-service, discovery-service are not available for a short period of time.
But I am not a purist at all and I would not have removed some functionality people is using (it is a question of freedom). So, an alternative solution is:
If it is working for you, then go ahead
Because I do not really understand why Docker suppressed the fantastic healthcheck command from v3.
Service dependency are always tricky when using docker-compose.
Your solution is acceptable because "there is no other way".
To avoid third-part libs, this is what I do in the same scenario:
In the Dockerfile I add netcat-openbsd, a bash file I call entrypoint and the application jar and then I run the entrypoint.sh.
FROM openjdk:8-jdk-alpine
RUN apk --no-cache add netcat-openbsd
COPY entrypoint.sh /opt/bin/
COPY app.jar /opt/lib/
RUN chmod 755 /opt/esusab-bi/bin/app/entrypoint.sh
The entrypoint file has the following instruction:
#!/bin/sh
while ! nc -z config 8888 ; do
echo "Waiting for upcoming Config Server"
sleep 2
done
java -jar /opt/lib/app.jar
It will delay the application start-up until your config server is up, without a specific interval.
The best solution is probably, as Carlos Cavero said, to make your application resilient to config-server failure. But you can also solve the problem by using the wait-for script from Eficode on Github.
Copy the script into your container and in your docker-compose.yml use:
client:
image: client-server:latest
environment:
JAVA_OPTS: -DEUREKA_SERVER=http://eureka:8761/eureka
depends_on:
- config
ports:
- 9000:9000
command: wait-for $CONFIGSERVER_SERVICE_NAME:$CONFIGSERVER_PORT -- java $JVM_OPTIONS -jar client.war $SPRING_OPTIONS
The environment variables for CONFIGSERVER_SERVICE_NAME and CONFIGSERVER_PORT can be defined in your Docker Compose environment file.
If you need to wait for multiple services, you can merge this pull request and list all needed services in the command line parameters such as:
command: wait-for $SERVICE1_NAME $SERVICE1_PORT $SERVICE2_NAME $SERVICE2_PORT -- java $JVM_OPTIONS -jar client.war $SPRING_OPTIONS
Just a friendly tip: You should not bind Config to Eureka but the other way around -> Eureka should be Config client.

spring-cloud-zuul timeout configuration does not work

according to spring cloud zuul 8.1.3 zuul timeout, the following configuration should make zuul timeout after 20 seconds, however, it times out at 10 seconds.
server:
port: 8769
spring:
application:
name: service-zuul
zuul:
host:
connect-timeout-millis: 20000
socket-timeout-millis: 60000
zuul:
routes:
tp:
path: /**
url: http://localhost:9998
ribbon:eureka:enabled: false
From console output one can see that the interval between filter and timeout exception is only 10 seconds. which means the zuul.host.connect-timeout-millis does not work.
I finally found a solution:
I used properties before and this is the first time to try yml, it seems that an item must be aggregated into one prefix:
zuul:
host:
connect-timeout-millis: 20000
socket-timeout-millis: 60000
routes:
tp:
path: /**
url: http://localhost:9998
In this way the backend server could have at most 60 seconds to respond. Besides, I also found that the sequence in configuration matters.
Try to define the below properties instead if you are using Zuul withe Eureka.
ribbon:
ReadTimeout: 60000
ConnectTimeout: 20000
If you are using Zuul with Eureka, Zuul will use RibbonRoutingFilter for routing instead of SimpleHostRoutingFilter. In this case, HTTP requests are handled by Ribbon.
Add the below config to Zuul gateway to make it work:
hystrix.command.default.execution.timeout.enabled= true
ribbon.ReadTimeout=5000
ribbon.ConnectTimeout=5000
#(ribbon.ReadTimeout + ribbon.connectTimeout) * (1+ribbon.maxAutoRetries(default 0) * (ribbon.MaxAutoRetriesNextServer (default 1) + 1)
#timeoutInMilliseconds= (5000 + 5000) * (1+0)*(1+1) =20000
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=21000
Note: Though the IDEs complain this is unknown property, it still works.

Yml config files "Inheritance" with Spring boot

I couldn't find a straight answer online.
Do Spring Boot's yml files "inherit" from each other? I mean if I have:
application.yml which has
server:
port: 80
host: foo
and application-profile1.yml which has only
server:
port: 90
So if I start my Spring Boot with profile1 as active profile, will I also have server.host property set to foo?
Yes, application.yml file has higher precedence over any application-{profile}.yml file. Properties from profile specific yml file will override values from the default application.yml file and properties that do not exist in profile specific yml file will be loaded from the default one. It applies to .properties files as well as to bootstrap.yml or bootstrap.properties.
Spring Boot documentation mentions it in 72.7 Change configuration depending on the environment paragraph:
In this example the default port is 9000, but if the Spring profile ‘development’ is active then the port is 9001, and if ‘production’ is active then it is 0.
The YAML documents are merged in the order they are encountered (so later values override earlier ones).
To do the same thing with properties files you can use application-${profile}.properties to specify profile-specific values.
Here is my solution.
Assume application.yml:
spring:
profiles: default-server-config
server:
port: 9801
servlet:
context-path: '/ctp'
If I want use default-server-config profile, and use port 8080 in my application-dev.yml
application-dev.yml:
spring:
profiles:
include:
- default-server-config
- dev-config
---
spring:
profiles: dev-config
server:
port: 8080
Then -Dspring.profiles.active=dev

Loadbalancing fails when a server is down

I have written a simple set of micro-services with the following architecture:
For all, I have added spring-boot-starter-actuator in order to add /health endpoint.
In Zuul/Ribbon configuration I have added :
zuul:
ignoredServices: "*"
routes:
home-service:
path: /service/**
serviceId: home-service
retryable: true
home-service:
ribbon:
listOfServers: localhost:8080,localhost:8081
eureka.enabled: false
ServerListRefreshInterval: 1
So that, each time client will call GET http://localhost:7070/service/home, loadbalancer will choose one of two HomeService which runs on 8080 or 8081 port and will call its endpoint /home.
But, when one of HomeService is shutdown, the loadbalancer does not seem to be aware (in spite of ServerListRefreshInterval configuration) and will fail with error=500 if it tries to call the shutdown instance.
How could I fix it?
I have received and tested a solution from spring-cloud team.
Solution is here in github
To summarize:
I have added org.springframework.retry.spring-retry to my zuul classpath
I have added #EnableRetry to my zuul application
I have put the following properties in my zuul configuration
application.yml
server:
port: ${PORT:7070}
spring:
application:
name: gateway
endpoints:
health:
enabled: true
sensitive: true
restart:
enabled: true
shutdown:
enabled: true
zuul:
ignoredServices: "*"
routes:
home-service:
path: /service/**
serviceId: home-service
retryable: true
retryable: true
home-service:
ribbon:
listOfServers: localhost:8080,localhost:8081
eureka.enabled: false
ServerListRefreshInterval: 100
retryableStatusCodes: 500
MaxAutoRetries: 2
MaxAutoRetriesNextServer: 1
OkToRetryOnAllOperations: true
ReadTimeout: 10000
ConnectTimeout: 10000
EnablePrimeConnections: true
ribbon:
eureka:
enabled: false
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 30000
Debugging timeouts may be tricky, considering there are 3 levels of routing alone (Zuul→Hystrix→Ribbon), not including async execution layers and the retry engine. The following scheme is valid for Spring Cloud releases Camden.SR6 and newer (I've checked this on Dalston.SR1):
Zuul routes the request through RibbonRoutingFilter, which creates a Ribbon command with the request context. Ribbon command then creates a LoadBalancer command, which uses spring-retry for command execution, choosing retry policy for the RetryTemplate according to Zuul settings. #EnableRetry does nothing in this case, because this annotation enables wrapping methods with #Retryable annotation in retrying proxies.
This means, your command duration is limited to the lesser value of these two (see this post):
[HystrixTimeout], which is a timeout for invoked Hystrix command
[RibbonTimeout * MaxAutoRetries * MaxAutoRetriesNextServer] (retries kick in only if Zuul has them enabled in its configuration), where [RibbonTimeout = ConnectTimeout + ReadTimeout] on the http client.
For debugging, it's convenient to create a breakpoint in RetryableRibbonLoadBalancingHttpClient#executeWithRetry or RetryableRibbonLoadBalancingHttpClient#execute method. At this point, you have:
ContextAwareRequest instance (e.g. RibbonApacheHttpRequest or OkHttpRibbonRequest) with request context, which containes Zuul's retryable property;
LoadBalancedRetryPolicy intsance with load balancer context, which contains Ribbon's maxAutoRetries, maxAutoRetriesNextServer and okToRetryOnAllOperations properties;
RetryCallback instance with a requestConfig, which contains HttpClient's connectTimeout and socketTimeout properties;
RetryTemplate instance with chosen retry policy.
If the breakpoint is not hit, it means that org.springframework.cloud.netflix.ribbon.apache.RetryableRibbonLoadBalancingHttpClient bean was not instantiated. This happenes when the spring-retry library is not in the classpath.

Resources