Http Pool Stats monitor using spring feign - spring

I am using spring feign, with connection pooling
implementation 'io.github.openfeign:feign-httpclient:12.1'
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign:3.1.5'
application.yml
feign:
httpclient:
enabled: true
maxConnections: 55
maxConnectionsPerRoute: 25
I want to print pool metrics using like this at scheduled intervals
#Autowired
HttpClient httpClient;
#Scheduled(fixedDelay = 1000)
public void printStats(){
((PoolingHttpClientConnectionManager) ((CloseableHttpClient) httpClient).getConnectionManager()).getTotalStats();
}
But the method getConnectionManager() is deprecated.
Any alternatives or better way of doing it.

Related

Spring cloud load-balancer drops instances after cache refresh

I have a need to save Spring Cloud Gateway routes within a database and to do this we send a web request using the WebClient to another microservice.
I'm using Eureka for service discovery and want the WebClient to use discovery instance names instead of explicit URLs and I've therefore utilised the #LoadBalanced annotation on the bean method:
#Bean
public WebClient loadBalancedWebClientBuilder(WebClient.Builder builder) {
return builder
.exchangeStrategies(exchangeStrategies())
.build();
}
#Bean
#LoadBalanced
WebClient.Builder builder() {
return WebClient.builder();
}
private ExchangeStrategies exchangeStrategies() {
return ExchangeStrategies.builder()
.codecs(clientCodecConfigurer -> {
clientCodecConfigurer.defaultCodecs().jackson2JsonEncoder(getEncoder());
clientCodecConfigurer.defaultCodecs().jackson2JsonDecoder(getDecoder());
}).build();
}
This all works on start-up and for the default 35s cache time - i.e. the webClient discovers the required 'saveToDatabase' service instance and sends the request.
On each eventPublisher.publishEvent(new RefreshRoutesEvent(this)) a call is made to the same downstream microservice (via the WebClient) to retrieve all saved routes.
Again this works initially, but after the default 35seconds the load balancer cache seems to be cleared and the downstream service id can no longer be found:
WARN o.s.c.l.core.RoundRobinLoadBalancer - No servers available for service: QUERY-SERVICE
I have confirmed it is the cache refresh purging the cache and not re-acquiring the instances by setting
spring:
application:
name: my-gateway
cloud:
loadbalancer:
cache:
enabled: true
ttl: 240s
health-check:
refetch-instances: true
ribbon:
enabled: false
gateway:
...
I've struggled with this for days now and cannot find/ see where or why the cache is not being updated, only purged. Adding specific #LoadBalancerClient() configuration as below makes no difference.
#Bean
public ServiceInstanceListSupplier instanceSupplier(ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder()
.withDiscoveryClient()
.withHealthChecks()
.withCaching()
.withRetryAwareness()
.build(context);
}
Clearly this must work for other people, so what am I missing?!
Thanks.

Can Spring Boot be configured to act as both client and server (mesh topology) with RabbitMQ RPC?

I have 2 apps developed with spring boot:
App1:
exposes an API for app2, for example /api/members
makes a call to app2 in order to retrieve weather details, for example /api/weather
App2:
exposes an API for app1, /api/weather
makes a call to app1 in order to retrieve member details, /api/members
The communication between them is made using HTTP at the moment. Is there a way to configure rabbitMQ inside spring boot to act as a consumer on an exchange, and a producer on another one? Would this be ok from the architectural POV? I could not find any articles related to this. Any links/ examples would be greatly appreciated.
I figured this one out:
This is the RabbitMQ config file:
#Configuration
class RabbitCfg {
#Bean
fun queue() = Queue("queueName")
#Bean
fun exchange() = DirectExchange("exc")
#Bean
fun binding(exchange: DirectExchange, queue: Queue) = BindingBuilder.bind(queue).to(exchange).with("routeKey")
#Bean
fun jsonMessageConverter() = Jackson2JsonMessageConverter(ObjectMapper())
}
Afterwards I am able to call from app1:
val response = rabbitTemplate.convertSendAndReceive(exchange.name, "otherRouteKey", req) as MyObj
and handle requests from app2 in the same spring boot project:
#Service
#RabbitListener(queues = ["queueName"])
class Receiver {
#RabbitHandler
fun handleMenuMessage(obj: MyObj) = OtherObj()
...
}
The only condition required is that both apps are configured on the same exchange, with different "routeKey" values.

Can I apply graceful shutdown when using Spring Cloud Stream Kafka 3.0.3.RELEASE?

I developed the kafka consumer application based on Spring Cloud Stream 3.0.3.RELEASE.
(SpringBoot 2.3.4.RELEASE)
When I stop this application,
I want the consumer to gracefully shut down. Similar Questions
Stop polling new messages
Finish their work and Commit the offset to Kafka
Gracefully shut down application
Does the spring cloud stream default this work?
Then is there a related document?
For your information, I am using spring cloud stream kafka as below.
#Message handler
#Component
public class MessageHandler {
#Bean
public Consumer<MyEvent> handleMessage() {
return message -> {...}
}
...
}
#application.yml
spring:
cloud:
stream:
bindings:
handleMessage-in-0:
destination: myevent
group: test-group
consumer:
maxAttempts: 2
concurrency: 10
function:
definition: handleMessage
...
As mentioned in the answer you referenced, you can increase the shutdownTimeout container property (default 10 seconds) with a ListenerContainerCustomizer bean.
#Bean
public ListenerContainerCustomizer<AbstractMessageListenerContainer<?, ?>> customizer() {
return (container, dest, group) -> container.getContainerProperties()
.setShutdownTimeout(30_000L);
}

SpringBoot Disable rabbitTemplate retry policy for rabbit health check

My SpringBoot configuration contains very strong retry policy for rabbitTemplate retries
spring:
rabbitmq:
template:
retry:
enabled: true
initial-interval: 500
max-attempts: 10
multiplier: 5
max-interval: 60000
The problem with this configuration is when health endpoint is called and rabbitMQ is down, the connections hangs for really long time.
Adding properties like
spring.rabbitmq.connection-timeout=500 or
spring.rabbitmq.template.receive-timeout=500 or
spring.rabbitmq.template.reply-timeout=500 or
spring.rabbitmq.requested-heartbeat=1
does not help, since the retry.multiplier=5, so it will take a lot of time anyway.
If we disregard whether the retry policy is good or not, is there a way to disable rabbitTemplate retries for health check endpoint or at least give it some timeout?
You can override the default health indicator bean to use a template without retry enabled...
#Configuration
public class MyRabbitHealthIndicatorOverride
extends CompositeHealthIndicatorConfiguration<RabbitHealthIndicator, RabbitTemplate> {
#Bean
public HealthIndicator rabbitHealthIndicator(ConnectionFactory connectionFactory) {
return createHealthIndicator(new RabbitTemplate(connectionFactory));
}
}

Spring configurable, high performance, metered http client instances

Coming from DropWizard I am used to its HttpClientConfiguration and I am baffled that in Spring Boot I cannot find some support for controlling in a similar manner http clients instances to be used, by RestTemplates for example.
To work in production the underlying client implementation should be high performance (e.g. non blocking io, with connection reuse and pooling).
Then I need to set timeouts or authentication, possibly metrics gathering, cookie settings, SSL certificates settings.
All of the above should be easy to set up in different variants for different instances to be used in different contexts (e.g. for service X use these settings and this pool, for Y use another pool and settings) and most parameters should be set via environment-specific properties to have different values in production/qa/development.
Is there something that can be used towards this end?
Below is an example of configuring a HttpClient with a configuration class. It configures basic authentication for all requests through this RestTemplate as well as some tweaks to the pool.
HttpClientConfiguration.java
#Configuration
public class HttpClientConfiguration {
private static final Logger log = LoggerFactory.getLogger(HttpClientConfiguration.class);
#Autowired
private Environment environment;
#Bean
public ClientHttpRequestFactory httpRequestFactory() {
return new HttpComponentsClientHttpRequestFactory(httpClient());
}
#Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate(httpRequestFactory());
restTemplate.setInterceptors(ImmutableList.of((request, body, execution) -> {
byte[] token = Base64.encodeBase64((format("%s:%s", environment.getProperty("fake.username"), environment.getProperty("fake.password"))).getBytes());
request.getHeaders().add("Authorization", format("Basic %s", new String(token)));
return execution.execute(request, body);
}));
return restTemplate;
}
#Bean
public HttpClient httpClient() {
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
// Get the poolMaxTotal value from our application[-?].yml or default to 10 if not explicitly set
connectionManager.setMaxTotal(environment.getProperty("poolMaxTotal", Integer.class, 10));
return HttpClientBuilder
.create()
.setConnectionManager(connectionManager)
.build();
}
/**
* Just for demonstration
*/
#PostConstruct
public void debug() {
log.info("Pool max total: {}", environment.getProperty("poolMaxTotal", Integer.class));
}
}
and an example application.yml
fake.username: test
fake.password: test
poolMaxTotal: 10
You can externalise configuration values to your application.yml as with poolMaxTotal etc. above.
To support different values per environment you can use Spring profiles. Using the example above, you could just create application-prod.yml with a "prod" specific value for poolMaxTotal. Then start your app with --spring.profiles.active=prod and the "prod" value will be used instead of your default value in application.yml. You can do this for however many environments you need.
application-prod.yml
poolMaxTotal: 20
For an async HttpClient, see here: http://vincentdevillers.blogspot.fr/2013/10/a-best-spring-asyncresttemplate.html

Resources