I am trying to customize the timeout settings for my couchbase Spring Boot client. I am using spring-boot-starter-data-couchbase in my project. Specifically what I want to do is, when it's taking too long for the couchbase to respond(may be say because of some network partition or any other reason). I just want to send some default response to my client. I followed this answer and am also using AbstractCouchbaseConfiguration to configure the timeout but it is just not working.
Below is the overridden method from my configuration class.
#Override
protected CouchbaseEnvironment getEnvironment() {
DefaultCouchbaseEnvironment.builder()
.connectTimeout(TimeUnit.SECONDS.toMillis(2))
.maxRequestLifetime(TimeUnit.SECONDS.toMillis(2))
.socketConnectTimeout(1000).queryTimeout(TimeUnit.SECONDS.toMillis(2));
return super.getEnvironment();
}
Can someone please help me with this?
Related
I am trying to connect to an existing Elasticsearch instance. The instance is set up and working fine, which I can confirm by accessing it through the browser under https://localhost:9200. I am using Spring Data Elasticsearch version 4.1.2 and I am following the official instructions from https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#elasticsearch.clients.rest.
Unfortunately, when starting the application, the initial health checks of the elasticsearch instance fail, because the code is trying to use http instead of https:
o.s.w.r.f.client.ExchangeFunctions : [377e90b0] HTTP HEAD http://localhost:9200/
Therefore I added the ".usingSsl()" to the ClientConfiguration, but it does not seem to have any effect and I just don't understand why. The "funny" thing is, if I implement the reactive client as described here (https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#elasticsearch.clients.reactive), https suddenly works and the applications starts perfectly fine. However, I want to use the regular high level client.
Can you help me change the configuration in a way so that it finally makes use of https instead of http?
#Configuration
class ElasticsearchClientConfig: AbstractElasticsearchConfiguration() {
#Bean
override fun elasticsearchClient(): RestHighLevelClient {
val clientConfiguration = ClientConfiguration.builder()
.connectedTo("localhost:9200")
.usingSsl()
.build();
return RestClients.create(clientConfiguration).rest();
}
}
I have an external requirement that I provide an endpoint to tell the load balancer to send traffic to my app. Much like the Kubernetes "readiness" probe, but it has to be a certain format and path, so I can just give them the actuator health endpoint.
In the past I've used the HealthEndpoint and called health(), but that doesn't work for reactive apps. Is there a more flexible way to see if the app is "UP"? At this level I don't care if it's reactive or servlet, I just want to know what Spring Boot says about the app.
I haven't found anything like this, most articles talk about calling /actuator/health, but that isn't what I need.
Edit:
Just a bit more detail, I have to return a certain string "NS_ENABLE" if it's good. There are certain conditions where I return "NS_DISABLE", so I can't just not return anything, which would normally make sense.
Also, I really like how Spring Boot does the checking for me. I'd rather not re-implement all those checks.
Edit 2: My final solution
The answers below got me very far along even though it wasn't my final solution, so I wanted to give a hint to my final understanding.
It turns out that the HealthEndpoint works for reactive apps just as well as servlet apps, you just have to wrap them in Mono.
How do we define health of any web servers?
We look at how our dependent services are, we check the status of Redis, MySQL, MongoDB, ElasticSearch, and other databases, this's what actuator does internally.
Actuator checks the status of different databases and based on that it returns Up/Down.
You can implement your own methods that would check the health of dependent services.
Redis is healthy or not can be checked using ping command
MySQL can be verified using SELECT 1 command or run some query that should always success like SHOW TABLES
Similarly, you can implement a health check for other services. If you find all required services are up then you can declare up otherwise down.
What about shutdown triggers? Whenever your server receives a shutdown signal than no matter what's the state of your dependent services, you should always say down, so that upstream won't send a call to this instance.
Edit
The health of the entire spring app can be checked programmatically by autowiring one or more beans from the Actuator module.
#Controller
public class MyHealthController{
#Autowired private HealthEndpoint healthEndpoint;
#GetMapping("health")
public Health health() {
Health health = healthEndpoint.health();
return healthEndpoint.health();
}
}
There're other beans related to health check, we can auto wire required beans. Some of the beans provide the health of the respective component, we can combine the health of each component using HealthAggregator to get the final Health. All registered health indicator components can be accessed via HealthIndicatorRegistry.
#Controller
public class MyHealthController{
#Autowired private HealthAggregator healthAggregator;
#Autowired private HealthIndicatorRegistry healthIndicatorRegistry;
#GetMapping("health")
public Health health() {
Map<String, Health> health = new HashMap<>();
for (Entry<String, HealthIndicator> entry : healthIndicatorRegistry.getAll().entrySet()) {
health.put(entry.getKey(), entry.getValue().health());
}
return healthAggregator.aggregate(health);
}
}
NOTE: Reactive component has its own health indicator. Useful classes are ReactiveHealthIndicatorRegistry, ReactiveHealthIndicator etc
Simple solution is to write your own health endpoint instead of depending on Spring.
Spring Boot provides you production-ready endpoints but if it doesn't satisfy your purpose, write your end-point. It will just return "UP" in response. If the service is down, it will not return anything.
Here's the spring boot documentation on writing reactive health endpoints. Folow the guide and should be enough for your usecase.
They also document on how to write liveliness and Readiness of your application.
https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html#reactive-health-indicators
Is there any way to refresh springboot configuration as soon as we change .properties file?
I came across spring-cloud-config and many articles/blogs suggested to use this for a distributed environment. I have many deployments of my springboot application but they are not related or dependent on one another. I also looked at few solutions where they suggested providing rest endpoints to refresh configs manually without restarting application. But I want to refresh configuration dynamically whenever I change .properties file without manual intervention.
Any guide/suggestion is much appreciated.
Can you just use the Spring Cloud Config "Server" and have it signal to your Spring Cloud client that the properties file changed. See this example:
https://spring.io/guides/gs/centralized-configuration/
Under the covers, it is doing a poll of the underlying resource and then broadcasts it to your client:
#Scheduled(fixedRateString = "${spring.cloud.config.server.monitor.fixedDelay:5000}")
public void poll() {
for (File file : filesFromEvents()) {
this.endpoint.notifyByPath(new HttpHeaders(), Collections
.<String, Object>singletonMap("path", file.getAbsolutePath()));
}
}
If you don't want to use the config server, in your own code, you could use a similar scheduled annotation and monitor your properties file:
#Component
public class MyRefresher {
#Autowired
private ContextRefresher contextRefresher;
#Scheduled(fixedDelay=5000)
public void myRefresher() {
// Code here could potentially look at the properties file
// to see if it changed, and conditionally call the next line...
contextRefresher.refresh();
}
}
We have a spring application where redis cache has been implemented along with the database MySQL. Here we are using redis cache to store the temporary values for the server validations instead of hitting the database every time, hence hitting the database calls every time gets reduces system performance.
Now i explain my problem while hitting the spring boot action endpoints,
if suddenly my redis cache server stops, we would like to know how to get the notification that my redis cache server is down. So we need solution / example java application to get the notification using redis cache listener context or anything like that.
Redis doesn't work that way. In fact, no remote service will notify your application that it's down. Usually, it's the other way round: If the service you're consuming is accessed with a more or less sophisticated client, you might take advantage of the client's features.
Asynchronous clients that run I/O, or monitoring threads can help here. More specific, it depends on the client you're using with Spring Boot and Redis. Jedis is a plain client that reacts on a request basis. Lettuce allows you to register a RedisConnectionStateListener that is called on specific connection events, such as connected/disconnected:
RedisClient redisClient = …;
redisClient.addListener(new RedisConnectionStateListener() {
#Override
public void onRedisConnected(RedisChannelHandler<?, ?> redisChannelHandler) {
}
#Override
public void onRedisDisconnected(RedisChannelHandler<?, ?> redisChannelHandler) {
}
#Override
public void onRedisExceptionCaught(RedisChannelHandler<?, ?> redisChannelHandler, Throwable throwable) {
}
});
When using Spring Data Redis, retrieving the RedisClient from LettuceConnectionFactory might be a bit tricky as it is a private field. Hence it requires reflection.
Spring cloud config client helps to change the properties in run time. Below are 2 ways to do that
Update GIT repository and hit /refresh in the client application to get the latest values
Update the client directly by posting the update to /env and then /refresh
Problem here in both the approaches is that there could be multiple instances of client application running in cloud foundry and above rest calls will reach any one of the instances leaving application in inconsistent state
Eg. POST to /env could hit instance 1 and leaves instance 2 with old data.
One solution I could think of is to continuously hit these end points "n" times using for loop just to make sure all instance will be updated but it is a crude solution. Do any body have better solution for this?
Note: We are deploying our application in private PCF environment.
The canonical solution for that problem is the Spring Cloud Bus. If your apps are bound to a RabbitMQ service and they have the bus on the classpath there will be additional endpoints /bus/env and /bus/refresh that broadcast the messages to all instances. See docs for more details.
Spring Cloud Config Server Not Refreshing
see org.springframework.cloud.bootstrap.config.RefreshEndpoint code here:
public synchronized String[] refresh() {
Map<String, Object> before = extract(context.getEnvironment()
.getPropertySources());
addConfigFilesToEnvironment();
Set<String> keys = changes(before,
extract(context.getEnvironment().getPropertySources())).keySet();
scope.refreshAll();
if (keys.isEmpty()) {
return new String[0];
}
context.publishEvent(new EnvironmentChangeEvent(keys));
return keys.toArray(new String[keys.size()]);
}
that means /refresh endpoint pull git first and then refresh catch,and public a environmentChangeEvent,so we can customer the code like this.